state & 生命周期
这个不是这一章的重点,但是下面的函数中有用到,所以先在这里提一下:
函数定义组件
比如下面这样形式的组件:
class Clock extends React.Component {
render(){
return (
<h1>{this.props.title}</h1>
);
}
}
可以简写成下面这样的函数形式
function Clock(props){
return (
<h1>{props.title}</h1>
);
}
ReactDOM.render(
<Clocl title='函数定义组件' />,
document.getElementById("root")
);
看上一篇中关于时钟组件的例子,这里我们不再外部设置定时任务,之后调用函数来重新渲染这样的方式,我们把上述全部功能封装进Clock
组件中。
为一个类添加局部状态
class Clock extends React.Component{
constructor(props){
super(props);
this.state={
date:new Date()
};
}
render(){
return (
<div>
<h1>定时器显示:</h1>
<h2>{this.state.date.toLocaleTimeString()}</h2>
</div>
);
}
}
ReactDOM.render(
<Clocl />,
document.getElementById('root')
);
还没有写完,上面只是把基本结构搭建出来了,并把实现显示从传入参数this.props.date.toLoaclTimeString()
的方式变成了this.state.date.toLocaleTimeString()
,该组件现在并不需要外部传递参数,组件本身就会显示时间,至于更新,看下面:
将生命周期方法添加到类中
这里先介绍两个函数:
- componentDidMount
- componentWillMount
关于这两个函数的简单介绍看这里,为了实现定时任务,我们设置在组件被渲染到DOM后的函数:componentDidMount中设置定时任务:
componentDidMount(){
this.timeID=setInterval(
()=>this.tick(),
1000
);
}
这里timeID
只是个随便设置的参数,重点是我们要设置该组件内部的tick()
函数每隔一秒运行一次。下面展示tick()
函数:
tick(){
this.setState(
{date:new Date()}
);
}
这里顺带再展示一下释放掉该定时任务:
componentWillMount(){
clearInterval(this.timeID);
}
下面说一下上面代码的运行顺序:
constructor()
运行,将组件私有属性state
中的date
设置成new Date()
,这里可以说是初始化。componentDidMount()
运行,设置定时运行tick()
函数- 在
tick()
函数中使用唯一能更新sate
的函数setState
更新state
- 在输出中输出
state
中的date
,就能把全部的时钟功能封装到一个组件内部了。 - 最后在该组件被释放掉时,删除掉定时任务,不再占用系统资源
正确地使用状态
不要直接更新状态
下面对state
直接赋值的方式是不会更新组件输出的:
this.state.date=new Date();
而是要使用函数setState
:
this.setState({date:new Date()})
状态更新可能是异步的
- 当你多次调用
setState()
时,React会把多次调用构建成一次调用,所以当你设置了setState()
可能不是立刻生效的 - 并且由于
this.props
和this.state
不是同步更新的,所以你最好不要靠这两者的值决定下一步的代码。
要想state
的值与prop
的值同步更新,可以使用下面的形式:
形式1:
this.setState((state,props)=>({
PropsName:state.firstName+" "+props.lastName
}));
形式2:
this.setState(function(state,props){
return {
PropsName:state.firstName+" "+props.lastName
};
});
状态更新合并
当你在constructor
中初始化state
时可能设置了多个值:
constructor(props){
super(props);
this.state={
posts:[],
comments:[]
};
}
当你下面单独更新其中一部分时:
this.setState(
{posts:'单独设置post的值'}
);
this.setState(
{comments:"这里单独设置comments"}
);
并不会影响另一个的设置,每个属性都是独立的!
数据自顶向下流动
比如我返回这么一个组件,这里用组件的简写形式:
function Clock(props){
return (
<h1>{props.date.toLocaleString()}</h1>
);
}
ReactDOM.render(
<Clock date={new Date} />,
document.getElementById("root")
);
在Clock
中,他并不需要关心props.date
的来源,只要知道该组件是父级组件传递进来的一个参数即可。