react的生命周期(二)
前面已經(jīng)詳細講解過react的生命周期棵里,具體可以參考我的另一篇文章:http://www.reibang.com/p/4be358fadb3d
React組件生命周期有三個階段:加載跑慕、更新和卸載。每個階段有多個方法來調用實現(xiàn)某些功能历极。這些方法名字也很有意思,帶will前綴表示在該階段發(fā)生之前調用,did表示在該階段發(fā)生之后調用。本文將介紹這些方法侣签。本文翻譯自React官網(wǎng)文檔,如有翻譯不當急迂,請不吝指正影所。
1. Mounting階段:
該階段表示一個組件實例被創(chuàng)建并被插入到DOM中。該階段有四個方法:constructor()僚碎,componentWillMount()猴娩,render()和componentDidMount()。
constructor(props):
該方法在組件加載前調用勺阐。當組件作為React.Component的子類實現(xiàn)時需要在其他聲明之前先調用super(props)卷中。否則,this.props在構造器中會是undefined渊抽,這會導致代碼出現(xiàn)bug蟆豫。
作用:
用來初始化狀態(tài),如果既不初始化狀態(tài)也不綁定方法懒闷,那就沒必要實現(xiàn)該方法了十减。(筆者注:事實上,如果組件沒有構造器方法的話愤估,組件會默認調用一個構造器帮辟,實現(xiàn)屬性的傳遞)。
componentWillMount():
該方法會在加載發(fā)生前調用玩焰。因為它發(fā)生在render()方法前由驹,因此在該方法內(nèi)同步設置狀態(tài)不會引發(fā)重渲染。該方法還是服務器端渲染的唯一的生命周期鉤子震捣。一般荔棉,推薦用constructor()代替該方法。
render():
該方法必須要有蒿赢。當調用時润樱,它會檢查this.props和this.state,然后返回一個React元素羡棵。這個元素可以是原生DOM組件如div壹若,也可以是一個自定義的復合組件。如果什么也不想渲染的話,可以返回null或false店展。當返回null或false時养篓,ReactDOM.findDOMNode(this)會返回null。該方法應該是純凈的赂蕴,這意味著它不能修改組件狀態(tài)柳弄,每次調用會返回相同的結果,不會和瀏覽器發(fā)生直接的交互概说。如果想要同瀏覽器發(fā)生交互的話碧注,應該在componentDidMount()中實現(xiàn)。
componentDidMount():組件加載完成后觸發(fā)糖赔。
作用:
放置必要的DOM節(jié)點萍丐。如果要從遠程節(jié)點加載數(shù)據(jù),這是一個不錯的實例化網(wǎng)絡請求的地方放典。也可以在此處設置定時器等逝变。
注意:在該方法內(nèi)設置狀態(tài)會導致重渲染。
2. Updating階段:
該階段表示由狀態(tài)或屬性的改變導致組件的重渲染奋构。該階段有五個方法:componentWillReceiveProps()壳影,shouldComponentUpdate(),componentWillUpdate()弥臼,render()和componentDidUpdate()态贤。
componentWillReceiveProps(nextProps):
該方法會在加載好的組件在收到新的狀態(tài)后調用。如果需要更新狀態(tài)以反映屬性的改變醋火,可以在比較this.props和nextProps后,使用this.setState()方法來實現(xiàn)狀態(tài)的過渡箱吕。
注意:React可能會在props值并未改變的時候調用該方法芥驳,所以要確保每次處理改變時都要比較當前props和收到的props值。這可能發(fā)生在父組件導致該組件重渲染時茬高。
非觸發(fā)時期:mounting階段不會調用該方法兆旬。只有在部分props屬性更新時調用該方法,另外調用this.state()不會觸發(fā)該方法怎栽。
shouldComponentUpdate(nextProps, nextState):該方法用來告訴React,組件輸出是否受到當前狀態(tài)或屬性的影響熏瞄。默認情況下脚祟,每次狀態(tài)改變都會導致重渲染强饮,在大多數(shù)情況下,你只需保持該默認行為即可。該方法在收到新的props或state時會被調用铭乾,且調用是在重渲染前。該方法默認返回true炕檩。但返回false不會影響其子組件在狀態(tài)改變時的重渲染。
非觸發(fā)時期:
初次渲染或使用forceUpdate()時不會調用該方法捌斧。
注意:就目前而言,如果該方法返回false骤星,以后的componentWillUpdate(),render()和componentDidUpdate()都不會再調用了洞难。但未來可能該方法返回的結果只是作為暗示副编,而非指令猖吴,返回false可能仍會導致重新渲染椰棘。
最后根时,如果找到了導致性能低下的組件鸦列,可以使它繼承React.PureComponent谒养。該組件用props和state的淺比較實現(xiàn)了shouldComponentUpdate()桶蝎。也可以自己實現(xiàn)該方法杠娱,通過this.props同nextProps比較编丘,this.state同nextState比較与学,然后返回false以跳過更新。
componentWillUpdate():
該方法在收到新屬性和狀態(tài)渲染前調用嘉抓∷魇兀可以用它來做更新前的準備工作。
注意:
該方法不可以調用this.setState()抑片。如果需要更新狀態(tài)以響應屬性的改變卵佛,使用componentWillReceiveProps(nextProps)代替。
非觸發(fā)時期:初次渲染不會調用該方法敞斋。shouldComponentUpdate()返回false不會調用該方法截汪。
render():
該方法是mount和update階段都會使用到的方法,解釋同mount階段的render()植捎。
非觸發(fā)時期:
shouldComponentUpdate()返回false不會調用該方法衙解。
componentDidUpdate(prevProps, prevState):
更新發(fā)生后會立即調用該方法⊙媸啵可用來在組件更新后操作DOM丢郊。另外盔沫,也可以通過比較當前屬性和之前屬性來決定是否發(fā)送網(wǎng)絡請求(如,狀態(tài)未改變不需要做網(wǎng)絡請求)枫匾。
非觸發(fā)時期:
初次渲染不會調用該方法架诞。shouldComponentUpdate()返回false不會調用該方法。
3. Unmounting階段:
該階段表示組件將從DOM中移除干茉。該階段只有一個方法:componentWillUnmount()谴忧。
componentWillUnmount():
該方法會在組件被銷毀前立即調用。
作用:
可以在方法內(nèi)實現(xiàn)一些清理工作角虫,如清除定時器沾谓,取消網(wǎng)絡請求或者是清理其他在componentDidMount()方法內(nèi)創(chuàng)建的DOM元素。
在組件的整個生命周期中戳鹅,隨著該組件的props或者state發(fā)生改變均驶,它的DOM表現(xiàn)也將有相應的改變,一個組件就是一個狀態(tài)機妇穴,對于特定的輸入腾它,它總會返回一致的輸出死讹。
React為每個組件提供了生命周期鉤子函數(shù)去響應不同的時刻——創(chuàng)建時、存在期及銷毀時妓忍。
生命周期方法
React的組件擁有簡潔的生命周期API愧旦,它僅僅提供你所需要的方法,而不會去最求全面。
實例化:
一個實例出吃被穿件時所調用的生命周期方法與其他哥哥后續(xù)實例被創(chuàng)建所調用的方法略有不同耕皮。當你首次使用一個組建類時蝙场,會看到下面這些方法依次被調用:
getDefaultProps
getInitialState
componentWillMount
render
ComponentDidMOunt
對于該組件類所有后續(xù)應用,你將會看到下面的方法依次被調用罚拟。注意:gerDefaultProps方法不在列表中。
getInitialState
componentWillMount
render
componentDidMount
存在期:
隨著應用狀態(tài)的改變赐俗,以及組件逐漸受到影響,你將會看到下面的方法一次被調用:
componentwillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
銷毀&清理期:
最后粱快,當該組件被使用完成后事哭,componentWillUnmount方法會被調用瓜富,目的是給這個實例提供清理自身的機會。
以下是詳細說明:
實例化:
當每個新的組件被創(chuàng)建首次渲染時谤辜,有一系列的方法可以用來為其做準備工作仅胞,這些方法中的每一個斗毆明確的職責,如下所示:
getDefaultProps
對于組件來說渠欺,這個方法只會調用一次挠将,對于那些沒有父輩組件指定的props屬性的新建實例來說编整,這個方法返回的對象可用與為實例設置默認的props值。
getInitalState:
對于組件的每個實例來說内贮,這個方法調用次數(shù)有且僅有一次汞斧,這里你將有機會初始化每個實例的state,與getDefaultProps方法不同的是,每次實例創(chuàng)建時該方法都會被調用一次竞端,這個方法中庙睡,可以訪問到this.props.
componentWillMount:
該方法在完成首次渲染之前被調用技俐,這也是在render方法調用前可以修改組件state的最后一次機會雕擂。
render:
在這里你創(chuàng)建一個虛擬DOM捂刺,用來表示組件的輸出募寨,對于一個組件來說,render是唯一一個必需的方法仪缸,并且有特定的規(guī)則列肢。render方法選要滿足下面幾點:
只能通過this.props和this.state訪問數(shù)據(jù)。
可以返回null拴还,false或者任何React組件欧聘。
只能出現(xiàn)一個頂級組件(不能返回一組元素)、
必須純凈费封,有位置不能改變組件狀態(tài)或者修改DOM輸出蒋伦。
componentDidMount:
在render方法成功調用并且真實的DOM已經(jīng)被渲染之后痕届,可以在componentDidMount內(nèi)部通過this.getDOMNode(方法訪問到它。
這就是你可以訪問原始DOM的生命周期的鉤子函數(shù)锤窑,當你需要測量DOM元素的高度或者使用計時器操作它或者運行jQuery插件時蓝撇,可以將這些操作掛載到這個方法上:
舉例來說渤昌,假設需要在一個通過React渲染出的表單元素上使用jQueryUI的Autocomplete插件,則可以這樣使用它:
//需要自動補全的字符串列表
var datasource =[...];
var MyComponent=React.crateClass({
render:function(){
rerurn <input .../>
},
componentDidMount:function(){
$(this.gerDOMNode()).autocomplete({
source:datasource
});
}
});
ps:當React運行在服務器端時候迈窟,componentdidmount方法不會被調用忌栅。
存在期:
此時組件已經(jīng)渲染好并且用戶可以與它進行交互,通常一次鼠標點擊湖员、手指點按或者鍵盤事件觸發(fā)一個時間處理器娘摔,隨著用戶改變了組件或則和整個應用的state唤反,便會有新的state流入組件樹,并且我們將會獲得操控它的機會肠缨。
componentWillReceiveProps:
任何時刻組件的props都可以通過父輩組件來更改晒奕,出現(xiàn)這種情況時,componentWillReceiveProps方法會被調用吴汪,你將獲得更改props方法及跟他關心state的機會蒸眠。例如:
componentWillReceiveProps:function(nextProps){
if(nextProps.checked !==undefined){
this.setState({
checked:nextProps.checked
});
}
}
shouleComponentUpdate:
調用shoulecomponentUpadte方法在組件渲染時進行精確優(yōu)化楞卡。如果某個組件或者它的任何子組件不需要渲染成新的props或則和state,則該方法返回false淘捡,返回false則是說明React要跳到render方法焦除,一屆位于render前后的鉤子函數(shù):componentWillUpadate和componentDidUpdate作彤。
該方法非必需的乌逐,并且大部分情況沒有必要使用它浙踢。
componentWillUpdate:
和componentwillMount:方法類似灿渴,組建會在收到新的props或者state進行渲染之前調用該方法。
注意:你不可以在該方法中更新huo或者props蹬挤。而應該借助componentWillreceiveProps方法在運行時更新state荸百。
componentDidUpdate:
和componentDidMount方法類似,該方法給我們更新已經(jīng)渲染好的DOM機會蓝翰。
銷毀&清理期
當React使用完一個組件女嘲,這個組件必須從DOM中卸載隨后被銷毀欣尼。此時僅有的一個狗子函數(shù)會做出響應,完成所有的清理和銷毀工作钙态。
componentWillUnmount:
最后菇晃,隨著組件從他的層級結構中移除,這個組件的生命也就走id熬了盡頭驻子,該方法會在組件被移除之前調用估灿,讓你有機會做一些清理工作。在componentDidMount方法中添加的所有任務都需要在該方法中撤銷域慷,比如穿件的定時器或者添加的事件監(jiān)聽器。
反模式:把計算后的值賦值給state:
getInitalState方法中兄纺,嘗試通過this.props來創(chuàng)建state的做法是一種反模式。React專注于維護數(shù)據(jù)的單一來源钦奋。它的設計使得傳遞數(shù)據(jù)的來源更加顯而易見,這激素和iReact的一個優(yōu)勢朦拖。
比如在組件中吧日期轉化成字符串形式厌衔,或者渲染之前字符串轉換為大寫富寿。這些都不是state,只能夠在渲染時進行計算苏潜。
當組件的state值和它基于的prop不同步变勇,因而無法了解到render函數(shù)內(nèi)部結構時,可以認定為一種反模式飞袋。
//反模式:經(jīng)過計算后值不應該賦給state
getDefaultProps:function(){
return{
date:newDate()
};
},
getInitalState:function(){
return{
day:this.props.date.getDay()
}
},
render:function(){
return <div>Day:{this.state.day}</day>
}
正確的模式應該是渲染時計算這些值巧鸭,保證了計算后的值永遠不會派生出它的props值不同步锣险。
//渲染時計算值是正確的
gerDefaultProps:function(){
return{
date:new Date()
};
}
render:function(){
var day = this.props.date.getDay();
return <div>Day:{day}</div>;
}
然而巷折,如果你的目的并不是同步崖咨,而只是簡單的初始化state,那么在getInitialState方法中使用props是沒問題的署拟,只是一定要明確你的意圖,比如prop添加initial前綴心包。
getDefaultProps:function(){
return{
initialValue:'some-dafault-value'
}馒铃;
},
getInitialState:function(){
return{
value:this.props.initialValue
};
},
render:function(){
return <div>{this.props.value}</div>
}
總結:
react生命周期提供了進行設計的鉤子函數(shù)区宇,會伴隨著組件整個生命周期。和狀態(tài)機類似议谷,每個組件都被設計成了能夠在整個生命周期中輸出穩(wěn)定、語義化的標簽芬首。
組件不會獨立存逼裆,隨著父組件將props推送給他們的子組件,以及那些子組件渲染它們自身的子組件你必須謹慎的考慮數(shù)據(jù)是如何流經(jīng)整個應用的艺晴。每一個子組件真正需要掌握多少數(shù)據(jù)封寞,哪個組件來控制應用的狀態(tài)仅财?這些涉及數(shù)據(jù)流了。
作者:龍波帝國------------------->打造我的IT帝國
歡迎交流盏求,在下扣號:724711690碎罚,請備注:前端技術交流