组件的生命周期(Life Cycle)包含三个阶段:挂载(Mounting)、更新(Updating)和卸载(Unmounting),在每一个阶段都会有相应的回调方法(也叫钩子)可供选择,从而能更好的控制组件的行为。php
在这个阶段,组件会完成它的首次渲染,先执行初始化,再被挂载到真实的DOM中,其中依次调用的方法有constructor()、componentWillMount()、render()和componentDidMount()。除了render(),其余三个方法都只会运行一次。json
1)constructor()服务器
在生命周期中,类的构造函数constructor()会率先被执行,用于初始化组件的状态、接收外部传递进来的数据、绑定成员方法的this指向等工做。dom
2)componentWillMount()异步
componentWillMount()方法会运行在render()以前,它是渲染以前的回调函数。不过,因为在这个方法中执行的任务都能提早到constructor()中,所以实际项目中不多会用到它。函数
3)render()post
render()是在定义组件时必须声明的方法,它是一个无反作用的纯函数,可根据组件的props和state获得一个React元素、null或false等返回值,而且在render()方法中不能调用改变组件状态的this.setState()方法。注意,将元素渲染到页面DOM中的工做都由React负责,而不是render()方法。性能
4)componentDidMount()优化
componentDidMount()方法会运行在render()以后,它是渲染以后的回调函数。此时组件已被挂载到页面中,能够执行DOM相关的操做,例如异步读取服务器中的数据并填充到组件中、调用jQuery代码等。this
下面的组件没有实际用途,仅仅是为了演示四个回调函数,其中componentWillMount()和componentDidMount()都成功调用了this.setState()方法。
class Btn extends React.Component { constructor(props) { super(props); this.state = { name: props.name }; } componentWillMount() { this.setState({age: 28}); } render() { return <button>{this.state.name}</button>; } componentDidMount() { $.post("server.php", {id:1}, json => { this.setState({age: json.data.age}); }, "json"); } }
引发组件更新(即从新渲染)的方式有三种,第一种是由父组件向下传递props(即调用父组件的render()方法)引发的更新,依次会调用五个方法:componentWillReceiveProps()、shouldComponentUpdate()、componentWillUpdate()、render()和componentDidUpdate()。第二种是经过改变自身state(即调用this.setState()方法)引发的更新,会忽略componentWillReceiveProps()方法,只执行四个回调函数。第三种是经过组件的forceUpdate()方法强制更新,只有后三个回调函数会被执行。在下面的组件中,定义了更新阶段的五个回调函数,而且点击按钮就会触发强制更新。
class Btn extends React.Component { constructor(props) { super(props); this.state = { name: "strick" }; } dot() { this.setState({name: "freedom"}); this.forceUpdate(); //强制更新 } componentWillReceiveProps(nextProps) { } shouldComponentUpdate(nextProps, nextState) { return true; } componentWillUpdate(nextProps, nextState) { } render() { return <button onClick={this.dot.bind(this)}>{this.state.name}</button>; } componentDidUpdate(prevProps, prevState) { } }
1)componentWillReceiveProps()
componentWillReceiveProps()方法经常使用于执行props更新后的逻辑,只有第一种更新方式才会调用它,该方法能接收一个名为nextProps的参数,表示父组件传递进来的新的props。当须要经过this.setState()方法将nextProps中的数据同步到内部状态时,要先比较nextProps和this.props中的值是否相同,再决定是否执行同步。因为在componentWillReceiveProps()中能调用this.setState()方法,所以为了不进入一个死循环,在调用this.setState()方法更新组件时就不会触发它。
2)shouldComponentUpdate()
shouldComponentUpdate()用于决定是否继续组件的更新,它能接收2个参数:nextProps和nextState,分别表示新的props和state,经过比较nextProps、nextState和组件当前的this.props、this.state能得出一个布尔类型的返回结果。当返回结果为false时,组件会中止更新,后续的componentWillUpdate()、render()和componentDidUpdate()也不会被执行。将这个方法使用恰当的话,能减小冗余的渲染,优化组件的性能。
3)componentWillUpdate()和componentDidUpdate()
componentWillUpdate()和componentDidUpdate()分别运行在render()以前和以后,它们都能接收2个参数,前者提供更新后的props和state,后者提供更新前的props和state。在componentWillUpdate()中,不能调用this.setState()方法,以避免发生没必要要的死循环。
当组件在从DOM中被卸载以前,会触发一个无参数的componentWillUnmount()方法。在该方法内适合作些清理的工做,例如清除定时器、移除多余的DOM元素等。下面演示了处理卸载的过程,限于篇幅省略了组件的构造函数和render()方法,只给出了关键代码。
class Btn extends React.Component { componentWillUnmount() { clearInterval(timeout); } } var container = document.getElementById("container"); ReactDOM.render(<Btn>提交</Btn>, container); ReactDOM.unmountComponentAtNode(container); //移除DOM中的组件
接下来用一张总的流程图(如图5所示)来讲明生命周期各个方法之间的关系,灰底的方法表示在其内部能调用this.setState()方法。
图5 组件生命周期流程图