摘要
React中的組件類似于狀態(tài)機,每個組件都被設(shè)計成為在其生命周期過程中輸出穩(wěn)定、語義化的標簽。React組件的生命周期大致可以分為:創(chuàng)建時,存在期及銷毀時。為了更好的控制每個生命周期環(huán)節(jié),React提供了對應(yīng)的鉤子函數(shù)。
簡介
我們知道React里面的組件其實就是一個簡單的函數(shù),這些函數(shù)完成了對數(shù)據(jù)和方法的封裝,來幫助我們分離應(yīng)用中的關(guān)注點,最終實現(xiàn)對頁面的渲染。在組件的生命周期中,由于用戶與應(yīng)用間的交互,組件的props和states也會隨之改變,相應(yīng)的DOM也會發(fā)生變化。
React將組件的生命周期大概分為三個階段:創(chuàng)建時,存在期及銷毀時。每個階段都對應(yīng)著特定的鉤子函數(shù)做出響應(yīng),接下來詳細看一下這三個階段。
創(chuàng)建時
一個實例初始化時調(diào)用的方法與其他各個后續(xù)實例創(chuàng)建時調(diào)用的方法略有不同。當我們首次初始化一個組件類的時候,會依次調(diào)用如下方法:
- getDefaultProps
- getInitialState
- componentWillMount
- render
- componentDidMount
對于該組件類的所有后續(xù)應(yīng)用,對比組件初始化過程,除了getDefaultProps方法,其他方法均會被調(diào)用:
- getInitialState
- componentWillMount
- render
- componentDidMount
存在期
初始化之后的組件會隨著應(yīng)用狀態(tài)的改變,逐漸受到影響,會有如下方法依次執(zhí)行:
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
- render
- componentDidUpdate
銷毀時
最后,該組件使用完成后,componentWillUnmount方法將會被調(diào)用。
三個階段對應(yīng)的函數(shù)調(diào)用如上所述,接下來看一下每個方法的具體含義及作用。
組件的常見屬性及方法
getDefaultProps
在組件類創(chuàng)建的時候調(diào)用一次,然后返回值被緩存下來。如果父組件沒有指定 props 中的某個鍵,則此處返回的對象中的相應(yīng)屬性將會合并到 this.props (使用 in 檢測屬性)。該方法在任何實例創(chuàng)建之前調(diào)用,因此不能依賴于 this.props。另外,getDefaultProps() 返回的任何復(fù)雜對象將會在實例間共享,而不是每個實例擁有一份拷貝。
getInitialState
在每次組件掛載前均會被調(diào)用,返回值會作為this.state的初始值。在該方法內(nèi)部允許調(diào)用this.props。
render
對于每一個組件來說,render()方法是必須的。render方法會創(chuàng)建一個虛擬DOM對象(比如<div/> 或者 React.DOM.div()),作為當前組件的一個輸出,同時React要求render方法滿足以下幾點要求:
- 只能出現(xiàn)一個頂級組件;
- 通過
this.props和this.state訪問數(shù)據(jù);- 可以返回
null,false或者任何React組件(當返回null或者false的時候,this.getDOMNode()將返回null。);- 盡量保證render函數(shù)不修改組件
state,不修改DOM的輸出,也不和瀏覽器交互,每次調(diào)用都返回相同結(jié)果。
說明:如果需要和瀏覽器交互,在 componentDidMount() 中或者其它生命周期方法中做這件事。保持render() 純粹,可以使服務(wù)器端渲染更加切實可行,也使組件更容易被理解。
propTypes
propTypes 對象允許驗證傳入到組件的 props(規(guī)定了組件props的類別與必須狀態(tài))。
var Test = React.createClass({
propTypes: {
requiredFunc: React.PropTypes.func.isRequired, // 函數(shù)且必須
requiredAny: React.PropTypes.any.isRequired, // 可以是任何格式且必須
bool: React.PropTypes.bool, // Boolean
func: React.PropTypes.func, // 函數(shù)
number: React.PropTypes.number, // 數(shù)字
string: React.PropTypes.string // 字符串
...
},
render:function(){
return <div/>
}
});
var component = React.render( <Test requiredFunc="bar" bool="true" requiredAny="a"/>,document.body);
mixins
雖然組件的原則就是模塊化,彼此之間相互獨立,但是有時候不同的組件之間可能會存在共享行為,所以 React 提供了 mixins 這種方式來處理這種問題。Mixin 就是用來定義一些方法,使用這個 mixin 的組件能夠自由的使用這些方法,所以 mixin 相當于組件的一個擴展。
// 定義SetIntervalMixin對象
var SetIntervalMixin = {
componentWillMount: function() {
this.intervals = [];
},
setInterval: function() {
this.intervals.push(setInterval.apply(null, arguments));
},
componentWillUnmount: function() {
this.intervals.map(clearInterval);
}
};
var TickTock = React.createClass({
mixins: [SetIntervalMixin], // 配置mixin數(shù)組,將SetIntervalMixin作為數(shù)組的元素
getInitialState: function() {
return {seconds: 0};
},
componentDidMount: function() {
this.setInterval(this.tick, 1000); // 調(diào)用mixin中的setInterval方法
},
tick: function() {
this.setState({seconds: this.state.seconds + 1});
},
render: function() {
return (
<p>
React has been running for {this.state.seconds} seconds.
</p>
);
}
});
React.render(
<TickTock />,
document.getElementById('example')
);
statics
statics 對象允許你定義靜態(tài)的方法,這些靜態(tài)的方法可以在組件類上調(diào)用。
var MyComponent = React.createClass({
statics: {
customMethod: function(foo) {
return foo === 'bar';
}
},
render: function() {
}
});
MyComponent.customMethod('bar'); // true
在這個塊兒里面定義的方法都是靜態(tài)的,意味著你可以在任何組件實例創(chuàng)建之前調(diào)用它們,這些方法不能獲取組件的 props 和 state。如果你想在靜態(tài)方法中檢查 props 的值,在調(diào)用處把 props 作為參數(shù)傳入到靜態(tài)方法。
displayName
displayName 字符串用于輸出調(diào)試信息。JSX 自動設(shè)置該值;
生命周期方法
組件的生命周期方法會在組件生命周期中某個確定的時間點執(zhí)行。
掛載: componentWillMount
服務(wù)器端和客戶端都只調(diào)用一次,在初始化渲染執(zhí)行之前立刻調(diào)用。如果在這個方法內(nèi)調(diào)用setState,render() 將會感知到更新后的 state,將會執(zhí)行僅一次,盡管 state 改變了。
掛載: componentDidMount
在初始化渲染執(zhí)行之后立刻調(diào)用一次,僅客戶端有效(服務(wù)器端不會調(diào)用)。在生命周期中的這個時間點,組件擁有一個 DOM 展現(xiàn),你可以通過 this.getDOMNode() 來獲取相應(yīng) DOM 節(jié)點。如果想和其它 JavaScript 框架集成,使用 setTimeout 或者 setInterval 來設(shè)置定時器,或者發(fā)送 AJAX 請求,可以在該方法中執(zhí)行這些操作。
注意:為了兼容 v0.9,DOM 節(jié)點作為最后一個參數(shù)傳入。你依然可以通過this.getDOMNode()
獲取 DOM 節(jié)點。
更新: componentWillReceiveProps
componentWillReceiveProps(object nextProps)
在組件接收到新的 props 的時候調(diào)用。在初始化渲染的時候,該方法不會調(diào)用。用此函數(shù)可以作為 react 在 prop 傳入之后, render() 渲染之前更新 state 的機會。老的 props 可以通過 this.props 獲取到。在該函數(shù)中調(diào)用 this.setState() 將不會引起第二次渲染。
componentWillReceiveProps: function(nextProps) { this.setState({ likesIncreasing: nextProps.likeCount > this.props.likeCount });}
注意:對于 state,沒有相似的方法: componentWillReceiveState。將要傳進來的 prop 可能會引起 state 改變,反之則不然。如果需要在 state 改變的時候執(zhí)行一些操作,請使用 componentWillUpdate。
更新: shouldComponentUpdate
boolean shouldComponentUpdate(object nextProps, object nextState)
在接收到新的 props 或者 state,將要渲染之前調(diào)用。該方法在初始化渲染的時候不會調(diào)用,在使用 forceUpdate 方法的時候也不會。如果確定新的 props 和 state 不會導(dǎo)致組件更新,則此處應(yīng)該 返回 false
。
shouldComponentUpdate: function(nextProps, nextState) { return nextProps.id !== this.props.id;}
如果 shouldComponentUpdate 返回 false,則 render() 將不會執(zhí)行,直到下一次 state 改變。(另外,componentWillUpdate 和 componentDidUpdate 也不會被調(diào)用。)默認情況下,shouldComponentUpdate 總會返回 true,在 state 改變的時候避免細微的 bug,但是如果總是小心地把 state 當做不可變的,在 render() 中只從 props 和state 讀取值,此時你可以覆蓋 shouldComponentUpdate 方法,實現(xiàn)新老 props 和 state 的比對邏輯。如果性能是個瓶頸,尤其是有幾十個甚至上百個組件的時候,使用 shouldComponentUpdate可以提升應(yīng)用的性能。
更新: componentWillUpdate
componentWillUpdate(object nextProps, object nextState)
在接收到新的 props 或者 state 之前立刻調(diào)用。在初始化渲染的時候該方法不會被調(diào)用。使用該方法做一些更新之前的準備工作。
注意:你不能在該方法中使用 this.setState()。如果需要更新 state 來響應(yīng)某個 prop 的改變,請使用 componentWillReceiveProps。
更新: componentDidUpdate
componentDidUpdate(object prevProps, object prevState)
在組件的更新已經(jīng)同步到 DOM 中之后立刻被調(diào)用。該方法不會在初始化渲染的時候調(diào)用。使用該方法可以在組件更新之后操作 DOM 元素。注意:為了兼容 v0.9,DOM 節(jié)點會作為最后一個參數(shù)傳入。如果使用這個方法,你仍然可以使用 this.getDOMNode() 來訪問 DOM 節(jié)點。
移除: componentWillUnmount
在組件從 DOM 中移除的時候立刻被調(diào)用。在該方法中執(zhí)行任何必要的清理,比如無效的定時器,或者清除在 componentDidMount 中創(chuàng)建的 DOM 元素。
參考
【1】《React引領(lǐng)未來的用戶界面開發(fā)框架》
【2】 React中文官網(wǎng)