- Mounting/組件掛載相關:
componentWillMount
componentDidMount
- Updating/組件更新相關:
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
componentDidUpdate
- Unmounting/組件移除相關:
componentWillUnmount
一、Mounting/組件掛載相關
componentWillMount
在組件掛載之前執行,但僅執行一次,即使多次重復渲染改組件,或者改變了組件的state。若希望該回到能執行多次,可以使用ReactDOM.unmountComponentAtNode移除掉已有的組件,然后再重新render。
var diva = document.getElementById('a'); var divb = document.getElementById('b'); var i=0; var Component1 = React.createClass({ componentWillMount:function(){ console.log(++i) }, render: function() { console.log(Date.now()); return <div name={this.props.name}>我只是一個安靜的div</div> } });
//觸發componentWillMount,render ReactDOM.render( <Component1 />, diva );
//未觸發componentWillMount,觸發render ReactDOM.render( <Component1 />, diva );
//觸發componentWillMount,render ReactDOM.render( <Component1 />, divb );
//未觸發componentWillMount,未觸發render ReactDOM.render( <Component1 />, divb );
componentDidMount
在組件掛載之后執行,同componentWillMount一樣,同一個組件重復渲染只執行一次,卸載組件后重新渲染可以重新觸發一次。
二、Updating/組件更新相關
componentWillReceiveProps
在組件接收到props的時間點之前調用,注意組件初始化渲染時不會調用。
var i = 0; var div = document.getElementById('a'), var div2 = document.getElementById('b'); var Component1 = React.createClass({ componentWillReceiveProps: function(){ console.log(i++) }, clickCb: function() { React.render( <Component1 />, div2 ); }, render: function() { return <div onClick={this.clickCb}>點我給下一個div掛載組件</div> } }); React.render( <Component1 />, div //初始化不會觸發componentWillReceiveProps ); React.render( <Component1 />, div //重復渲染會觸發componentWillReceiveProps ); React.unmountComponentAtNode(div); //移除掉已有組件 React.render( <Component1 />, div //初始化不會觸發componentWillReceiveProps );
運行結果如下:

該接口帶有一個參數nextProps,可以利用它來獲取新的props的值(this.props獲取到的是當前的,也就是舊的props)
var i = 0; var div = document.getElementById('a'); var render = function(){ React.render( <Component1 i={i++} />, div ); }; var Component1 = React.createClass({ componentWillReceiveProps: function(nextProps){ console.log(this.props.i, nextProps.i) }, render: function() { return <div onClick={render}>props.i的值是:{this.props.i}</div> } }); render();
運行結果如下

shouldComponentUpdate
該接口實際是在組件接收到了新的props或者新的state的時候會立即調用,然后通過返回值來決定是否要重新渲染當前的組件。
接口帶兩個參數,第一個參數表示新的props,第二個參數表示新的state。
var div = document.getElementById('a'); var Component1 = React.createClass({ getInitialState: function(){ return { i : 0 } }, shouldComponentUpdate: function(nextProps, nextState){ console.log( this.state.i, nextState.i ); return nextState.i > 3 ? true : false; //返回true才會渲染組件 }, clickCb: function(){ this.setState({ i : this.state.i + 1 }) }, render: function() { return <div onClick={this.clickCb}>state.i的值是:{this.state.i}</div> } }); ReactDOM.render( <Component1 />, div );
點擊第四次之后才會渲染組件,在div里顯示正確的新state.i

componentWillUpdate
同shouldComponentUpdate一樣,在組件收到新的props或者state的時候會調用,而且也有着兩個參數來獲取新的props和state。
不過本接口僅在shouldComponentUpdate執行並返回了true的時候才會被調用。
在上一個代碼實例中做點改動
componentWillUpdate: function(nextProps, nextState){ console.log( 'yoyoyo', this.state.i, nextState.i ); },

componentDidUpdate
在組件更新,重新渲染完畢之后調用,它和componentWillUpdate一樣有着兩個參數來獲取新的props和state
var div = document.getElementById('a'); var Component1 = React.createClass({ getInitialState: function(){ return { i : 0 } }, shouldComponentUpdate: function(nextProps, nextState){ console.log( this.state.i, nextState.i ); return nextState.i > 3 ? true : false; //返回true才會執行componentWillUpdate並重新渲染組件 }, componentDidUpdate: function(nextProps, nextState){ console.log( '已經渲染完畢咯', this.state.i, nextState.i ); }, componentWillUpdate: function(nextProps, nextState){ console.log( '還沒渲染哦', this.state.i, nextState.i ); }, clickCb: function(){ this.setState({ i : this.state.i + 1 }) }, render: function() { return <div onClick={this.clickCb}>state.i的值是:{this.state.i}</div> } }); ReactDOM.render( <Component1 />, div );
運行結果如下:

三、Unmounting/組件移除相關:
var div = document.getElementById('a'); var div2 = document.getElementById('b'); var Component1 = React.createClass({ DOMArr : [], getInitialState: function(){ return { i : 0 } }, componentDidUpdate: function(nextProps, nextState){ var dom = document.createElement('p'); dom.innerText = this.state.i; div2.appendChild(dom); this.DOMArr.push(dom); }, componentWillUnmount: function(){ if(!this.DOMArr.length) return; var i = 0; while(i < this.DOMArr.length){console.log(i); div2.removeChild(this.DOMArr[i++]); //移除componentDidUpdate里添加過的DOM } }, clickCb: function(){ this.setState({ i : this.state.i + 1 }) }, render: function() { return <div onClick={this.clickCb}>state.i的值是:{this.state.i}</div> } }); ReactDOM.render( <Component1 />, div ); div2.addEventListener('click',function(){ ReactDOM.unmountComponentAtNode(div) //點擊div2則卸載掉第一個div里的組件 }, false)
運行結果如下:

四、getDefaultProps和getInitialState
getDefaultProps
該方法是所有我們提及的方法中最先觸發的,可以在該方法里return 一個對象來作為組件默認的props值(如果父組件傳進來了props,以父組件為主),它只在組件初次掛載到頁面上時觸發,即使你重新掛載了組件。
getInitialState
用於給組件初始化state的值,調用該方法要求必須return 一個對象或者null,否則報錯。該方法在組件每次實例化的時候都會觸發。
var diva = document.getElementsByTagName('div')[0], divb = document.getElementsByTagName('div')[1]; var Component1 = React.createClass({ getDefaultProps: function(){ console.log('getDefaultProps'); return { name : Date.now() } }, getInitialState: function(){ console.log('getInitialState'); return null; //必須返回一個null或對象,否則會報錯 }, render: function() { console.log(Date.now()); return <div name={this.props.name}>我只是一個安靜的div</div> } }); ReactDOM.render( {/* 觸發一次 getDefaultProps 和 getInitialState */} <Component1 />, diva ); ReactDOM.render( {/* getDefaultProps 和 getInitialState都不觸發 */} <Component1 />, diva ); ReactDOM.unmountComponentAtNode(diva); ReactDOM.render( {/* 觸發一次getInitialState */} <Component1 name="a"/>, diva ); ReactDOM.render( {/* 觸發一次getInitialState */} <Component1/>, divb );
五、總結
上面是9個周期接口,它們被觸發的順序?
var Component1 = React.createClass({ getDefaultProps: function(){ console.log('getDefaultProps') }, getInitialState: function(){ console.log('getInitialState'); return null }, componentWillMount: function(){ console.log('componentWillMount') }, componentDidMount: function(){ console.log('componentDidMount') }, componentWillReceiveProps: function(){ console.log('componentWillReceiveProps') }, shouldComponentUpdate: function(){ console.log('shouldComponentUpdate'); return true; }, componentWillUpdate: function(){ console.log('componentWillUpdate') }, componentDidUpdate: function(){ console.log('componentDidUpdate') }, componentWillUnmount: function(){ console.log('componentWillUnmount') }, render: function() { return <div>我只是一個安靜的div</div> } }); ReactDOM.render( <Component1 />, document.body ); ReactDOM.render( <Component1 />, document.body ); ReactDOM.unmountComponentAtNode(document.body)
結果如下:

