一. State:
与props类似,但是是组件内部私有的,完全受控于组件内部的数据。
开始使用state
- 首先,创建class组件
class Clock extends React.Component {
render () {
return (
<div>
<h1> Hello </h1>
<h2> Now, it is {this.state.date.toLocaleTimeString()}</h2>
</div>
);
}
}
- 新建constructor构造函数,在构造函数中添加this.state的初始化赋值
constructor (props) {
super(props)
this.state = {date: new Date()};
}
问题:为什么要在constructor第一行进行super(props)调用,详见https://blog.csdn.net/huangpb123/article/details/85009024
完整代码:
class Clock extends React.Component {
constructor (props) {
super(props);
this.state={date:new Date()};
}
render() {
return (
<div>
<h1> Hello, world </h1>
<h2> Now is {this.state.date.toLocaleTimeString()}</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById("root")
)
这时,我们通过state获取时间,但还不能每1秒进行更新
需要借助生命周期实现周期性更新时间的效果
二. 生命周期
- 生命周期方法(类比Vue钩子函数)
用法:在组件处于某种生命周期状态时,执行某些操作
结合实例需求,需要每秒钟更新this.state.date的值
思路为:
当Clock被“挂载”到真实Dom上时,开启一个计时器,该计时器每一秒更新一次this.state.date的内容;当Clock组件被删除时,再将计时器清除
componentDidMount()函数,则为组件“挂载”阶段
componentWillUnmount()函数,则为组件卸载阶段
故,相应的,在componentDidMount()中,定义开启计时器操作:
componentDidMount() {
this.timerID = setInterval( //为了方便销毁计时器,需要设置计时器Id
() => this.tick(),1000
)
}
在componentWillUnmount()中,则销毁计时器:
componentWillUnmount() {
clearInterval(this.timerID);
}
最后,我们需要实现在计时器中的tick()方法:
关键函数:必须使用this.setState()方法更新state,因为只有setState()才能让React实现响应式数据效果,即“监测”到state的变化并重新渲染组件(与Vue处理data属性实现数据响应式原理不同)
tick() {
this.setState({date: newDate()}); //更新‘date’ state
}
总代码:
class Clock extends React.Component {
constructor (props) {
super(props);
this.state={date:new Date()};
}
componentDidMount() {
this.timerID = setInterval(
()=> this.tick() , 1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({date:new Date()});
}
render() {
return (
<div>
<h1> Hello, world </h1>
<h2> Now is {this.state.date.toLocaleTimeString()}</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById("root")
)
State的三个注意事项:
- 不要直接修改state值,请使用setState(),构造函数是唯一给this.state赋值的地方
- state的更新可能是异步(也可以是同步的)的,当需要依赖state和props更新state时,请通过给setState()传入一个函数的方法确保新state的正确性:
this.setState(function(state,props) { //每次的state都是最新的state,即异步调用成功后的state
return {counter: state.counter+props.increment};
})
- State的更新会合并
对于相同的key的state,只有最后一次的更新生效,即去重
小难点:如果想基于异步变化的state结果进一步进行操作,需要借助函数式的setState()写法(即第2点中的形式)把每一次的异步结果“连”起来,形成类似“同步”的效果。参考内容:
https://www.jianshu.com/p/799b8a14ef96
三. 数据流向
数据始终是从父组件流向子组件,父组件中可以通过state,或手写或props来向子组件传递数据,即自组件的props,子组件无从知道数据的具体来源,也无需知道。
有state的组件叫有状态组件,没有的叫无状态组件,可任意穿插使用