紧接上一章节示例,通过将生命周期(Lifestyle)添加到类组件来实现动态时钟组件。
在具有很多组件的web应用中,一定要注意当组件实例被销毁时,要及时释放其所占用的资源。如下所示,在React组件生成的React元素被加载到DOM中,则会运行componentDidMount()方法(在此方法中创建计时器);当这个React元素从DOM中被移除时则会运行componentWillUnmount()方法(在此方法中销毁计时器,回收系统资源)。
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>反清复明</h1>
<p>现在时间是:{this.state.date.toLocaleTimeString()}</p>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
上述过程如下所述:
<Clock />即根据Clock组件生成React元素,因为需要显示当前时间,故而使用this.state来出存储时间对象;ComponentDidMount()方法,来创建一个计时器;tick()方法,该方法会通过调用setState()来计划进行一次状态更新,当元素对象的状态更新,UI则随之更新;componentWillUnmount()方法来移除计时器以回收系统资源。对于state状态的更新,请使用setState()方法进行更新,而不要直接修改state。(constructor(props)初始化构造函数是唯一可以直接对this.state进行赋值的地方)
// 错误,UI不会发生改变
this.state.date = new Date();
// 正确,UI会随之重新渲染
this.setState({ date: new Date() });
State的更新是异步的(this.state和this.props的更新都是异步的);因此,若要更新state,就不应直接依赖这些异步更新的对象的值,这样是不安全准确的。解决方式就是通过使用函数的方式,利用函数中局部变量的独立性,来保证state更新的安全。
// 错误,依赖了异步更新的 this.state
this.setState({
counter: this.state.counter + 1,
});
// 正确,使用函数的方式来避免直接更新
this.setState(function(state) {
return {
counter: state.counter + 1
};
});
// 同样正确,使用箭头函数来简化普通的函数
this.setState((state) => ({
counter: state.counter + 1
}));
上面的例子中只是依赖了this.state,再举一个同时依赖了this.state和this.props的例子,函数的形参设2个即可:
// 错误,依赖了异步更新的 this.state
this.setState({
counter: this.state.counter + this.props.increment,
});
// 正确,使用函数的方式来避免直接更新
this.setState(function(state) {
return {
counter: state.counter + props.increment
};
});
// 同样正确,使用箭头函数来简化普通的函数
this.setState((state) => ({
counter: state.counter + props.increment
}));