紧接上一章节示例,通过将生命周期(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 }));