在組件的整個(gè)生命周期中伦籍,隨著該組件的props或者state發(fā)生改變瘾晃,其DOM表現(xiàn)也會(huì)有相應(yīng)的變化贷痪。一個(gè)組件就是一個(gè)狀態(tài)機(jī),對(duì)于特定地輸入酗捌,它總返回一致的輸出呢诬。
一個(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
對(duì)于每個(gè)組件實(shí)例來講典阵,這個(gè)方法只會(huì)調(diào)用一次,該組件類的所有后續(xù)應(yīng)用镊逝,getDefaultPops 將不會(huì)再被調(diào)用壮啊,其返回的對(duì)象可以用于設(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è)配置對(duì)象狸眼,用于定義屬性類型:
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 如下:
https://segmentfault.com/img/remote/1460000004840554/view
getInitialState
對(duì)于組件的每個(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 是對(duì)于組件類來說只調(diào)用一次瘸恼,后續(xù)該類的應(yīng)用都不會(huì)被調(diào)用劣挫,而 getInitialState 是對(duì)于每個(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狼钮,用來表示組件的輸出碳柱。對(duì)于一個(gè)組件來講,render方法是唯一一個(gè)必需的方法熬芜。render方法需要滿足下面幾點(diǎn):
1.只能通過 this.props 和 this.state 訪問數(shù)據(jù)(不能修改)
2.可以返回 null,false 或者任何React組件
3.只能出現(xiàn)一個(gè)頂級(jí)組件莲镣,不能返回一組元素
4.不能改變組件的狀態(tài)
5.不能修改DOM的輸出
render方法返回的結(jié)果并不是真正的DOM元素,而是一個(gè)虛擬的表現(xiàn)涎拉,類似于一個(gè)DOM tree的結(jié)構(gòu)的對(duì)象瑞侮。react之所以效率高,就是這個(gè)原因鼓拧。
componentDidMount
該方法不會(huì)在服務(wù)端被渲染的過程中調(diào)用半火。該方法被調(diào)用時(shí),已經(jīng)渲染出真實(shí)的 DOM季俩,可以再該方法中通過 this.getDOMNode() 訪問到真實(shí)的 DOM(推薦使用 ReactDOM.findDOMNode())钮糖。
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抬探。
componentDidUpdate
這個(gè)方法和 componentDidMount 類似,在組件重新被渲染之后帆赢,componentDidUpdate(object prevProps, object prevState) 會(huì)被調(diào)用小压∠吖#可以在這里訪問并修改 DOM。
銷毀時(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é)組件的生命周期: