在組件的整個(gè)生命周期中,隨著該組件的props或者state發(fā)生改變,其DOM表現(xiàn)也會(huì)有相應(yīng)的變化。一個(gè)組件就是一個(gè)狀態(tài)機(jī),對于特定地輸入,它總返回一致的輸出。
一個(gè)React組件的生命周期分為三個(gè)部分:實(shí)例化、存在期和銷毀時(shí)。
實(shí)例化
當(dāng)組件在客戶端被實(shí)例化,第一次被創(chuàng)建時(shí),以下方法依次被調(diào)用:
1、getDefaultProps
2、getInitialState
3、componentWillMount
4、render
5、componentDidMount
當(dāng)組件在服務(wù)端被實(shí)例化,首次被創(chuàng)建時(shí),以下方法依次被調(diào)用:
1、getDefaultProps
2、getInitialState
3、componentWillMount
4、render
componentDidMount 不會(huì)在服務(wù)端被渲染的過程中調(diào)用。
getDefaultProps
對于每個(gè)組件實(shí)例來講,這個(gè)方法只會(huì)調(diào)用一次,該組件類的所有后續(xù)應(yīng)用,getDefaultPops 將不會(huì)再被調(diào)用,其返回的對象可以用于設(shè)置默認(rèn)的 props(properties的縮寫) 值。
var Hello = React.creatClass({
getDefaultProps: function(){
return {
name: 'pomy',
git: 'dwqs'
}
},
render: function(){
return (
<div>Hello,{this.props.name},git username is {this.props.dwqs}</div>
)
}
});
ReactDOM.render(<Hello />, document.body);
也可以在掛載組件的時(shí)候設(shè)置 props:
var data = [{title: 'Hello'}];
<Hello data={data} />
或者調(diào)用 setProps (一般不需要調(diào)用)來設(shè)置其 props:
var data = [{title: 'Hello'}];
var Hello = React.render(<Demo />, document.body);
Hello.setProps({data:data});
但只能在子組件或組件樹上調(diào)用 setProps。別調(diào)用 this.setProps 或者 直接修改 this.props。將其當(dāng)做只讀數(shù)據(jù)。
React通過 propTypes 提供了一種驗(yàn)證 props 的方式,propTypes 是一個(gè)配置對象,用于定義屬性類型:
var survey = React.createClass({
propTypes: {
survey: React.PropTypes.shape({
id: React.PropTypes.number.isRequired
}).isRequired,
onClick: React.PropTypes.func,
name: React.PropTypes.string,
score: React.PropTypes.array
...
},
//...
})
組件初始化時(shí),如果傳遞的屬性和 propTypes 不匹配,則會(huì)打印一個(gè) console.warn 日志。如果是可選配置,可以去掉.isRequired。常用的 PropTypes 如下:
getInitialState
對于組件的每個(gè)實(shí)例來說,這個(gè)方法的調(diào)用有且只有一次,用來初始化每個(gè)實(shí)例的 state,在這個(gè)方法里,可以訪問組件的 props。每一個(gè)React組件都有自己的 state,其與 props 的區(qū)別在于 state只存在組件的內(nèi)部,props 在所有實(shí)例中共享。
getInitialState 和 getDefaultPops 的調(diào)用是有區(qū)別的,getDefaultPops 是對于組件類來說只調(diào)用一次,后續(xù)該類的應(yīng)用都不會(huì)被調(diào)用,而 getInitialState 是對于每個(gè)組件實(shí)例來講都會(huì)調(diào)用,并且只調(diào)一次
var LikeButton = React.createClass({
getInitialState: function() {
return {liked: false};
},
handleClick: function(event) {
this.setState({liked: !this.state.liked});
},
render: function() {
var text = this.state.liked ? 'like' : 'haven\'t liked';
return (
<p onClick={this.handleClick}>
You {text} this. Click to toggle.
</p>
);
}
});
ReactDOM.render(
<LikeButton />,
document.getElementById('example')
);
每次修改 state,都會(huì)重新渲染組件,實(shí)例化后通過 state 更新組件,會(huì)依次調(diào)用下列方法:
1、shouldComponentUpdate
2、componentWillUpdate
3、render
4、componentDidUpdate
但是不要直接修改 this.state,要通過 this.setState 方法來修改。
componentWillMount
該方法在首次渲染之前調(diào)用,也是再 render 方法調(diào)用之前修改 state 的最后一次機(jī)會(huì)。
render
該方法會(huì)創(chuàng)建一個(gè)虛擬DOM,用來表示組件的輸出。對于一個(gè)組件來講,render方法是唯一一個(gè)必需的方法。render方法需要滿足下面幾點(diǎn):
1.只能通過 this.props 和 this.state 訪問數(shù)據(jù)(不能修改)
2.可以返回 null,false 或者任何React組件
3.只能出現(xiàn)一個(gè)頂級組件,不能返回一組元素
4.不能改變組件的狀態(tài)
5.不能修改DOM的輸出
render方法返回的結(jié)果并不是真正的DOM元素,而是一個(gè)虛擬的表現(xiàn),類似于一個(gè)DOM tree的結(jié)構(gòu)的對象。react之所以效率高,就是這個(gè)原因。
componentDidMount
該方法不會(huì)在服務(wù)端被渲染的過程中調(diào)用。該方法被調(diào)用時(shí),已經(jīng)渲染出真實(shí)的 DOM,可以再該方法中通過 this.getDOMNode() 訪問到真實(shí)的 DOM(推薦使用 ReactDOM.findDOMNode())。
var data = [..];
var comp = React.createClass({
render: function(){
return <imput .. />
},
componentDidMount: function(){
$(this.getDOMNode()).autoComplete({
src: data
})
}
})
由于組件并不是真實(shí)的 DOM 節(jié)點(diǎn),而是存在于內(nèi)存之中的一種數(shù)據(jù)結(jié)構(gòu),叫做虛擬 DOM (virtual DOM)。只有當(dāng)它插入文檔以后,才會(huì)變成真實(shí)的 DOM 。有時(shí)需要從組件獲取真實(shí) DOM 的節(jié)點(diǎn),這時(shí)就要用到 ref 屬性:
var Area = React.createClass({
render: function(){
this.getDOMNode(); //render調(diào)用時(shí),組件未掛載,這里將報(bào)錯(cuò)
return <canvas ref='mainCanvas'>
},
componentDidMount: function(){
var canvas = this.refs.mainCanvas.getDOMNode();
//這是有效的,可以訪問到 Canvas 節(jié)點(diǎn)
}
})
需要注意的是,由于 this.refs.[refName] 屬性獲取的是真實(shí) DOM ,所以必須等到虛擬 DOM 插入文檔以后,才能使用這個(gè)屬性,否則會(huì)報(bào)錯(cuò)。
存在期
此時(shí)組件已經(jīng)渲染好并且用戶可以與它進(jìn)行交互,比如鼠標(biāo)點(diǎn)擊,手指點(diǎn)按,或者其它的一些事件,導(dǎo)致應(yīng)用狀態(tài)的改變,你將會(huì)看到下面的方法依次被調(diào)用
1、componentWillReceiveProps
2、shouldComponentUpdate
3、componentWillUpdate
4、render
5、componentDidUpdate
componentWillReceiveProps
組件的 props 屬性可以通過父組件來更改,這時(shí),componentWillReceiveProps 將來被調(diào)用??梢栽谶@個(gè)方法里更新 state,以觸發(fā) render 方法重新渲染組件。
componentWillReceiveProps: function(nextProps){
if(nextProps.checked !== undefined){
this.setState({
checked: nextProps.checked
})
}
}
shouldComponentUpdate
如果你確定組件的 props 或者 state 的改變不需要重新渲染,可以通過在這個(gè)方法里通過返回 false 來阻止組件的重新渲染,返回 `false 則不會(huì)執(zhí)行 render 以及后面的 componentWillUpdate,componentDidUpdate 方法。
該方法是非必須的,并且大多數(shù)情況下沒有在開發(fā)中使用。
shouldComponentUpdate: function(nextProps, nextState){
return this.state.checked === nextState.checked;
//return false 則不更新組件
}
componentWillUpdate
這個(gè)方法和 componentWillMount 類似,在組件接收到了新的 props 或者 state 即將進(jìn)行重新渲染前,componentWillUpdate(object nextProps, object nextState) 會(huì)被調(diào)用,注意不要在此方面里再去更新 props 或者 state。
銷毀時(shí)
componentWillUnmount
每當(dāng)React使用完一個(gè)組件,這個(gè)組件必須從 DOM 中卸載后被銷毀,此時(shí) componentWillUnmout 會(huì)被執(zhí)行,完成所有的清理和銷毀工作,在 componentDidMount 中添加的任務(wù)都需要再該方法中撤銷,如創(chuàng)建的定時(shí)器或事件監(jiān)聽器。
當(dāng)再次裝載組件時(shí),以下方法會(huì)被依次調(diào)用:
1、getInitialState
2、componentWillMount
3、render
4、componentDidMount
反模式
在 getInitialState 方法中,嘗試通過 this.props 來創(chuàng)建 state 的做法是一種反模式。
//反模式
getDefaultProps: function(){
return {
data: new Date()
}
},
getInitialState: function(){
return {
day: this.props.date - new Date()
}
},
render: function(){
return <div>Day:{this.state.day}</div>
}
經(jīng)過計(jì)算后的值不應(yīng)該賦給 state,正確的模式應(yīng)該是在渲染時(shí)計(jì)算這些值。這樣保證了計(jì)算后的值永遠(yuǎn)不會(huì)與派生出它的 props 值不同步。
//正確模式
getDefaultProps: function(){
return {
data: new Date()
}
},
render: function(){
var day = this.props.date - new Date();
return <div>Day:{day}</div>
}
如果只是簡單的初始化 state,那么應(yīng)用反模式是沒有問題的。
總結(jié)
以下面的一張圖總結(jié)組件的生命周期:

原文:http://www.ido321.com/1653.html