在組件的整個生命周期中胆筒,隨著該組件的props或者state發(fā)生改變,其DOM表現(xiàn)也會有相應(yīng)的變化酱酬。一個組件就是一個狀態(tài)機(jī)壶谒,對于特定地輸入,它總返回一致的輸出膳沽。
一個React組件的生命周期分為三個部分:實例化汗菜、存在期和銷毀時。
實例化
當(dāng)組件在客戶端被實例化挑社,第一次被創(chuàng)建時陨界,以下方法依次被調(diào)用:
1、getDefaultProps
2痛阻、getInitialState
3菌瘪、componentWillMount
4、render
5阱当、componentDidMount
當(dāng)組件在服務(wù)端被實例化俏扩,首次被創(chuàng)建時,以下方法依次被調(diào)用:
1弊添、getDefaultProps
2录淡、getInitialState
3、componentWillMount
4油坝、render
componentDidMount 不會在服務(wù)端被渲染的過程中調(diào)用嫉戚。
getDefaultProps
對于每個組件實例來講,這個方法只會調(diào)用一次澈圈,該組件類的所有后續(xù)應(yīng)用彬檀,getDefaultPops 將不會再被調(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è)置 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
提供了一種驗證 props 的方式,propTypes
是一個配置對象慈俯,用于定義屬性類型:
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
...
},
//...
})
組件初始化時渤刃,如果傳遞的屬性和 propTypes
不匹配,則會打印一個 console.warn 日志贴膘。如果是可選配置卖子,可以去掉.isRequired。常用的 PropTypes 如下:
[圖片上傳失敗...(image-9dfed6-1583734909257)]
getInitialState
對于組件的每個實例來說刑峡,這個方法的調(diào)用有且只有一次洋闽,用來初始化每個實例的 state玄柠,在這個方法里,可以訪問組件的 props诫舅。每一個React組件都有自己的 state羽利,其與 props 的區(qū)別在于 state只存在組件的內(nèi)部,props 在所有實例中共享刊懈。
getInitialState 和 getDefaultPops 的調(diào)用是有區(qū)別的这弧,getDefaultPops 是對于組件類來說只調(diào)用一次,后續(xù)該類的應(yīng)用都不會被調(diào)用虚汛,而 getInitialState 是對于每個組件實例來講都會調(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卷哩,都會重新渲染組件蛋辈,實例化后通過 state 更新組件,會依次調(diào)用下列方法:
1将谊、shouldComponentUpdate
2梯浪、componentWillUpdate
3、render
4瓢娜、componentDidUpdate
但是不要直接修改 this.state挂洛,要通過 this.setState 方法來修改。
componentWillMount
該方法在首次渲染之前調(diào)用眠砾,也是再 render 方法調(diào)用之前修改 state 的最后一次機(jī)會虏劲。
render
該方法會創(chuàng)建一個虛擬DOM,用來表示組件的輸出褒颈。對于一個組件來講柒巫,render方法是唯一一個必需的方法。render方法需要滿足下面幾點:
只能通過 this.props 和 this.state 訪問數(shù)據(jù)(不能修改)
可以返回 null,false 或者任何React組件
只能出現(xiàn)一個頂級組件谷丸,不能返回一組元素
不能改變組件的狀態(tài)
不能修改DOM的輸出
render方法返回的結(jié)果并不是真正的DOM元素堡掏,而是一個虛擬的表現(xiàn),類似于一個DOM tree的結(jié)構(gòu)的對象刨疼。react之所以效率高泉唁,就是這個原因。
componentDidMount
該方法不會在服務(wù)端被渲染的過程中調(diào)用揩慕。該方法被調(diào)用時亭畜,已經(jīng)渲染出真實的 DOM,可以再該方法中通過 this.getDOMNode()
訪問到真實的 DOM(推薦使用 ReactDOM.findDOMNode()
)迎卤。
var data = [..];
var comp = React.createClass({
render: function(){
return <imput .. />
},
componentDidMount: function(){
$(this.getDOMNode()).autoComplete({
src: data
})
}
})
由于組件并不是真實的 DOM 節(jié)點拴鸵,而是存在于內(nèi)存之中的一種數(shù)據(jù)結(jié)構(gòu),叫做虛擬 DOM (virtual DOM)。只有當(dāng)它插入文檔以后劲藐,才會變成真實的 DOM 八堡。有時需要從組件獲取真實 DOM 的節(jié)點,這時就要用到 ref
屬性:
var Area = React.createClass({
render: function(){
this.getDOMNode(); //render調(diào)用時聘芜,組件未掛載秕重,這里將報錯
return <canvas ref='mainCanvas'>
},
componentDidMount: function(){
var canvas = this.refs.mainCanvas.getDOMNode();
//這是有效的,可以訪問到 Canvas 節(jié)點
}
})
需要注意的是厉膀,由于 this.refs.[refName]
屬性獲取的是真實 DOM 溶耘,所以必須等到虛擬 DOM 插入文檔以后,才能使用這個屬性服鹅,否則會報錯凳兵。
存在期
此時組件已經(jīng)渲染好并且用戶可以與它進(jìn)行交互,比如鼠標(biāo)點擊企软,手指點按庐扫,或者其它的一些事件,導(dǎo)致應(yīng)用狀態(tài)的改變仗哨,你將會看到下面的方法依次被調(diào)用
1形庭、componentWillReceiveProps
2、shouldComponentUpdate
3厌漂、componentWillUpdate
4萨醒、render
5、componentDidUpdate
componentWillReceiveProps
組件的 props 屬性可以通過父組件來更改苇倡,這時富纸,componentWillReceiveProps 將來被調(diào)用≈冀罚可以在這個方法里更新 state,以觸發(fā) render 方法重新渲染組件晓褪。
componentWillReceiveProps: function(nextProps){
if(nextProps.checked !== undefined){
this.setState({
checked: nextProps.checked
})
}
}
shouldComponentUpdate
如果你確定組件的 props 或者 state 的改變不需要重新渲染,可以通過在這個方法里通過返回 false
來阻止組件的重新渲染综慎,返回 `false 則不會執(zhí)行 render 以及后面的 componentWillUpdate涣仿,componentDidUpdate 方法。
該方法是非必須的示惊,并且大多數(shù)情況下沒有在開發(fā)中使用好港。
shouldComponentUpdate: function(nextProps, nextState){
return this.state.checked === nextState.checked;
//return false 則不更新組件
}
componentWillUpdate
這個方法和 componentWillMount 類似,在組件接收到了新的 props 或者 state 即將進(jìn)行重新渲染前涝涤,componentWillUpdate(object nextProps, object nextState) 會被調(diào)用媚狰,注意不要在此方面里再去更新 props 或者 state。
componentDidUpdate
這個方法和 componentDidMount 類似阔拳,在組件重新被渲染之后,componentDidUpdate(object prevProps, object prevState) 會被調(diào)用『Γ可以在這里訪問并修改 DOM辨宠。
銷毀時
componentWillUnmount
每當(dāng)React使用完一個組件,這個組件必須從 DOM 中卸載后被銷毀货裹,此時 componentWillUnmout 會被執(zhí)行嗤形,完成所有的清理和銷毀工作,在 componentDidMount 中添加的任務(wù)都需要再該方法中撤銷弧圆,如創(chuàng)建的定時器或事件監(jiān)聽器赋兵。
當(dāng)再次裝載組件時,以下方法會被依次調(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)過計算后的值不應(yīng)該賦給 state船庇,正確的模式應(yīng)該是在渲染時計算這些值吭产。這樣保證了計算后的值永遠(yuǎn)不會與派生出它的 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é)組件的生命周期:
-https://image-static.segmentfault.com/315/625/3156257312-56761eb64bbfc