- 初识React及属性和状态的基本用法:https://blog.youkuaiyun.com/nwpu_geeker/article/details/79011147
- 可复用的html结构
无状态组件
- 无状态组件:就是一个普通的函数(它里面没有生命周期,没有state,有props)
- 无状态组件:使用构造函数创建,接收一个pops,返回一个react元素
- 优点:解析速度快,因为它是单纯展示内容的。
- props是单项数据流,只能来使用,不能修改
function Head(){
return <div></div>
}
有状态组件
- 有状态组件:基于class关键字创建组件(es6中关键字是实现面向对象编程的新新式)
- 有状态组件有生命周期,有state,props.
es6class关键字的作用
- 创建构造函数
- 必须使用new关键字来使用
- 不会使用
- class是一个语法糖
- 方法都是直接定以在原型上
- class 中constructor的基本使用
- 注意点
class 组件名 extends React.Component{
constructor(props){
super(props) //super必须加上
}
render(){
return 出来的就是将来组件要渲染的模板
return <div></div>
}
}
展示组件(Presentational component)和容器组件(Container component)之间有何不同
- 展示组件关心组件看起来是什么。展示专门通过 props 接受数据和回调,并且几乎不会有自身的状态,但当展示组件拥有自身的状态时,通常也只关心 UI 状态而不是数据的状态。
- 容器组件则更关心组件是如何运作的。容器组件会为展示组件或者其它容器组件提供数据和行为(behavior),它们会调用 Flux actions,并将其作为回调提供给展示组件。容器组件经常是有状态的,因为它们是(其它组件的)数据源。
修改状态必须setDate
- 设置state状态语法
// 正确
this.setState({title: 'React'});
- setState修改组件状态
。setState方法由Component所提供的
。当我们调用这个函数的时候,React.js会更新组件的状态state,并且重新调用render方法,然后在把render方法所渲染的最新的内容显示到页面上
this.setState是一个异步方法,有两个参数,第一个是要合并的状态对象,第二个是回调函数
this.setState({
count:this.state.count+1;
},()=>{ //这是第二个参数 ,因为是异步加载,这样视图和状态的内容才是一致。
console.log(this.state.count)
})
- *** 你调用setState的时候,React.js并不会马上修改state,而是把这个对象放到一个更新队列里面,稍后才会从当前队列里面把新的状态提取出来合并到state当中,然后再触发组件更新
state vs props
state是让组件控制自己的状态,props是让外部对组件自己记性配置
state
- state的作用主要作用是用于组件保存,控制,修改自己的可变状态,state在组件内部初始化,可以被组件自身修改,而外部不能访问也不能修改props
2.props
- props的主要作用是让使用该组件的父组件可以传入参数来配置该组件,它是外部传过来的配置参数,组件内部无法控制也无法修改,除非外部组件注定传入新的props,f否则组件的props保持不变
组件通信
- 父向子:
props 子:this.props
- 子向父:通过回调函数实现的
父:传一个函数 子:this.props.函数();
在子组件里面控制父组件的显示隐藏
以下为例:
--------------------------------------------------------------------------
《子组件》
state={
flag:""
}
let {flag}=this.state;
<div>onClick={this.handClick.bind(this,flag)}传flag过去</div>
handClick(flag){
this.props.hidden(flag,可以传多个参数)
}
-------------------------------------------------------------------------------
《父组件》
定义一个状态
state={
none:false, //穆恩
}
hidden={this.hiddenList.bind(this)} //给当前的父组件添加事件
let {none}=this.state;
{none ? <PageSocket_Item></PageSocket_Item> :null} //none为true,显示,none为false,不显示
//正常添加事件
hiddenList(flag){
let {none}=this.state
this.setState({
falg:none, //将传过来的flag赋值给none;
})
this.setState({
none:!none //改变none的状态。
})
}
- 非父子:没有关系的组件通信:(兄弟传参),详情见下文(非父子传参封装代码)
通过发布订阅来实现
非父子传参封装代码(兄弟)
- 将封装好的代码放在一个公共的文件夹里面,正常引入
- bus.emit()传参
- bus.on() 接收参数
class EventBus{
// add:[f1,f2,f3]
// del:[f1,f2]
constructor(){
this.event = {};
}
on(eventname,ck){
if(this.event[eventname] instanceof Array){
this.event[eventname].push(ck) //有了这个,就直接push进去
} else {
this.event[eventname] = [ck] //第一次,创造一个条件,放在这个回调里面
}
console.log(eventname,ck);
}
emit(eventname,...arg){
console.log(eventname,arg);
this.event[eventname] && this.event[eventname].map(item => {
item(...arg)
})
}
}
export default new EventBus();
下面的调用方法其实就是页面一和页面二的调用方法的,就是在调用上面的的on和emit,因为js是单线程的,按照顺序执行下去。这个就是来调用非父子组件的。(就是在不同的页面去调用,然后每个页面调用下面的额逻辑是不一样的,传参不同|要把相同的事件名里面的不同的的回调函数存在一个数组里面去调用)
// bus.on('add',(arg)=>{
// console.log(arg,'这是第一个');
// })
// bus.on('add',(arg)=>{
// console.log(arg,312);
// })
// bus.emit('add','1701B','周一');
// // bus.emit('del','1701B','周一');
- 跨组件通信(爷孙传参)
context上下文来实现 {Provider(提供者,Consumer(消费者))}
注意如果是多个文件跨组件传值,需要把React.Createcontext()放在一个公共的文件里面,然后抛出。
引入之后怎么使用
- 里面的value是固定语法,不可以改变
//公共文件
import React,{Component} from "react"
export default React.createContext()
//爷爷组件
import Context from "../utils/context"
<Context.Provider value={{val:this.state.val}}>
//这里写组件
<Context.Provider>
//孙子组件
import Context from "../utils/context"
<Context.Consumer>
{
value => {
return <p>{value.val}</p>
}
}
</Context.Consumer>
import