應對生命週期的是組件的生命週期函數,在組件從創建,加載,到最後刪除的這段週期裏,不同的時間點,React 框架都會調用組件的不同的生命週期函數。這些函數被調用時,本質上是框架在傳達信息,它告訴我們,組件當前正在處於某個特殊的時間點上。
生命週期函數就是組件本身具備的一些被框架在適當時間調用的固定接口而已,先看幾個比較重要的幾個周期函數:
1,componentWillMount
2,componentDidMount
3,componentWillUnmount
4,componentWillUpdate
5,componentDidUpdate
6, shouldComponentUpdate
7,componentWillRecieveProps
通過構建實例來看看這些函數是怎麼發揮作用的
例:
var CounterParent = React.createClass({
getDefaultProps: function() {
console.log("getDefaultProps:receive props from outsize");
return {};
},
getInitialState:function() {
console.log("getInitialiState:set default state object");
return {};
},
componentWillMount: function() {
console.log("componentWillMount:component is about to mount");
return;
},
componentDidMount: function() {
console.log("componentDidMount:component is just mount");
},
render: function() {
var s = "CounterParent rendering...."
return (
<div>
{s}
</div>
)
}
})
ReactDOM.render(
<div>
<CounterParent/>
</div>,
destination
);
幾個函數的調用次序如下:
1, 先被調用的是getDefaultProps 函數,在這個函數初始化this.props 對象
2,接着被調用的是getInitialState接口,這個接口用於初始化組件的state對象。
3, 接着被調用的是componentWillMount, 這是組件繪製前最後一個個被調用的接口,這個接口被調用之後,React框架就會調用組件的render函數,把組件繪製到界面上,
注意:在這例如果調用setState接口來改變組件的state對象的話,那麼render 接口將不會被框架調用。
繼續添加代碼,以便後續分析,新代碼更新如下:
接着也給CounterParent也妝點一下:
var CounterParent = React.createClass({
....
render: function() {
var backgroundStyle = {
padding: 50,
border: "#333 2px dotted",
width: 250,
height: 100,
borderRadius: 10,
textAlign: "center"
};
return (
<div style={backgroundStyle}>
<button> + </button>
</div>
)
});
給組件添加了一個加號按鈕,還沒有深入研究組件如何響應用戶輸入,
再創建一個子組件,用來顯示一個計數信息,當點擊加號按鈕時,可以讓計數加一,代碼如下:
var Counter = React.createClass({
render: function() {
var textStyle = {
fontSize: 72,
fontFamily: "sans-serif",
color: "#333",
fontWeight: "bold"
};
return (
<div style={textStyle}>
{this.props.display}
</div>
)
}
});
它將作爲CounterParent的一個子組件,所以在CounterParent的render函數裏要調用它:
var CounterParent = React.createClass({
...
render: function() {
var backgroundStyle = {
padding: 50,
border: "#333 2px dotted",
width: 250,
height: 100,
borderRadius: 10,
textAlign: "center"
}
}
return (
<div style={backgroundStyle}>
<Counter display="0"/>
<button> + </button>
</div>
)
});
完成上面代碼後,加載到瀏覽器後,發現在加號按鈕的上面多了一大大的數字0.但現在點擊按鈕時,上面數字沒有反應 。要想讓組件根據應用場景變化的話,就得需要組件的狀態對象機制,因此給CounterParent組件添加相關的狀態信息。代碼如下:
var CounterParent = React.createClass({
...
getInitialState: function() {
console.log("getInitialiState: set default state object");
return {
border: "#333 2px dotted",
width: 250,
height: 100,
borderRadius: 10,
textAlign: "center"
};
}
....
render: function() {
var backgroundStyle = {
padding: 50,
border: "#333 2px dotted",
width: 250,
height: 100,
borderRadius: 10,
textAlign: "center"
};
return (
<div style={backgroundStyle}>
<Counter display={this.state.count}/>
<button> + </button>
</div>
)
}
....
});
點擊加號按鈕時,數值能自動增加,因此需要添加加號按鈕點擊後的響應函數,代碼如下:
var CounterParent = React.createClass({
...
increase: function() {
this.setState({
count: this.state.count + 1
});
},
....
render: function() {
var backgroundStyle = {
padding: 50,
border: "#333 2px dotted",
width: 250,
height: 100,
borderRadius: 10,
textAlign: "center"
};
return (
<div style={backgroundStyle}>
<Counter display={this.state.count}/>
<button onClick="this.increase"> + </button>
</div>
)
}
....
});
state 更新流程:
把計數變量存儲在state對象的count變 中,每次按鈕點擊時 ,它的onClick事件被出發,然後調用increase函數,在該函數裏它通過setState改變state對象中count變 的值,state對象改變後,react 框架自動調用組件的render函數,於是新的計數值便繪製到界面上。
接下來組件的狀態對象改變後所引發的一系列周期函數調用。當點擊加號按鈕後,increase函數被調用,它再調用setState函數改變組件的state對象,進而引發React框架對組件接口的一系列調用。state對象改變後組件的shouldComponentUpdate 接口先被調用。
shouldComponentUpdate的邏輯:
var CounterParent = React.createClass({
shouldComponentUpdate: function(newProps, newState) {
console.log("shouldComponentUpdate: Should component update?");
if (newState.count < 5) {
console.log("Component should update");
return true;
} else {
console.log("Component should not update!");
return false;
}
},
});
該函數被框架調用後,如果返回true那麼React框架將繼續執行組件更新的相關流程,直到最後調用render函數,如果返回false,那麼React框架將終止更新流程,不會調用render函數。
框架調用該接口時,傳入兩個參數,分別是newProps,這個參數對應的是組件的屬性對象,也就是props對象,第二個參數是更新後的state對象,在代碼中,判斷state對象裏面的count變量它的值是否比5大,如果大過5,那麼返回false,這樣當持續點擊按鈕,計數數字會持續增加,但一旦增加到5的時候,再點擊按鈕界面上的數值就不會增加了。
如果返回true的話,React框架將調用組件的componentWillUpdate 接 ,把代碼添加上:
componentWillUpdate: function(newProps, newState) {
console.log("componentWillUpdate: Component is about to update");
},
這個函數調用後,框架就會調用render函數更新界面了,最後調用的接口是componentDidUpdate,代碼如下:
componentDidUpdate: function(currentProps, currentState) {
console.log("componentDidUpdate: component just updated");
return;
},
完成代碼後,在每個函數裏面添加斷點,然後點擊一下加號按鈕可以看到,首先componentShouldUpdate, componentWillUpdate 先後被調 ,然後render被調 ,於是界面上的計數信息更改,接着componentDidUpdate繼續被調用。嘗試繼續點擊按鈕,讓計數增加超過5後看看效果。
組件的消亡流程
當組件被刪除時,在它被銷燬前,它的接口componentWillUnmount 將會被調用,添加相關代碼如下:
componentWillUnmount: function() {
console.log("componentWillUnmount: component is removing from DOM");
return;
},
爲了觸發組件的銷燬事件,在計數增長到5時,調用ReactAPI:ReactDOM.unmountComponentAtNode 將加載的組件從DOM中刪除掉,這樣unmout事件就能被觸發了,代碼修改如下:
shouldComponentUpdate: function(newProps, newState) {
console.log("shouldComponentUpdate: Should component update?");
if (newState.count < 5) {
console.log("Component should update");
return true
} else { console.log(" Component should not update!");
ReactDOM.unmountComponentAtNode(destination);
return false;
}
},
分別在else 和componentWillUnmount函數中設置斷點,然後點擊按鈕,讓數值增加到5,可以發現一旦unmountComponentAtNode調用之後,componentWillUnmount 接着被調用,最後組件被框架從DOM中拿掉,於是 上面顯示的信息也消失了
結論:
可以看到,常使用的組件,看似平淡無奇,但當深入解剖它的運行機制時,會發現另外一個隱藏着的難以察覺的運行機制,React框架一直在監視着組件的狀態,並在合適的時機通過調用周期函數的方式通知我們,瞭解和掌握好react組件的命週期機制,對今後開發更復雜的網頁運用會打下堅實的基礎。