React-Native生命週期詳解

一.React-Native生命週期

 

說到生命週期,大家大概也能想到就是創建、銷燬、狀態改變。RN的組件就是一個狀態機。它接收兩個輸入參數:props和state,返回一個Virtual DOM。和Native一樣,RN也爲我們提供相應的鉤子函數。RN的狀態變化取決於props和state。我們先來看一張經典圖。

這張圖涵蓋了一個組件從創建、運行到銷燬的整個過程。大家可以看到,初始化的時候會調用5個函數(按先後順序)。這5個函數在整個組件被創建到銷燬的過程中只調用一次。初始化完畢後,當組件的props或者state改變都會觸發不同的鉤子函數,繼而引發組件的重新渲染。現在我們把這過程拆開一點一點來分析。

初始化

我們先來看初始化,在初始化的過程中,會按順序調用下面5個函數。

getDefaultProps:組件實例創建前調用,多個實例間共享引用。注意:如果父組件傳遞過來的Props和你在該函數中定義的Props的key一樣,將會被覆蓋。

getInitalState:組件示例創建的時候調用的第一個函數。主要用於初始化state。注意:爲了在使用中不出現空值,建議初始化state的時候儘可能給每一個可能用到的值都賦一個初始值。

componentWillMount:在render前,getInitalState之後調用。僅調用一次,可以用於改變state操作。

render:組件渲染函數,會返回一個Virtual DOM,只允許返回一個最外層容器組件。render函數儘量保持純淨,只渲染組件,不修改狀態,不執行副操作(比如計時器)。

componentDidMount:在render渲染之後,React會根據Virtual DOM來生成真實DOM,生成完畢後會調用該函數。在瀏覽器端(React),我們可以通過this.getDOMNode()來拿到相應的DOM節點。然而我們在RN中並用不到,在RN中主要在該函數中執行網絡請求,定時器開啓等相關操作

下面我們來演示getDefaultProps初始化Props以及父組件覆蓋問題(AppConnect和Provider是和redux相關的代碼,大家請跳過這一行):

比如我們在這裏定義了SimpleApp的默認Props爲一個key爲name,value爲wsd的字典(ES6以後廢除了getDefaultProps而使用上述方式),然後我們在它的父組件App中傳入一個同樣key爲name的Props,然後我們在SimpleApp中使用this.props.name把props打印出來,如下:

可以看到,原先的wsd被後面傳入的kingStart覆蓋了。

然後我們來看初始化State的演示(ES6裏使用constructor):

我們初始化一個state爲key爲sex,value爲boy的state對象,然後我們在componentWillMount函數中改變已經初始化的sex和沒有聲明的age,最後在render中打印:

可以看到我們在render中打印出了state中兩個屬性的值。在這裏我們需要注意的是,如果在componentWillMount中直接修改state的值不會引發render的再次渲染。而如果把修改state的操作放到在render執行完之後的componentDidMount中,是會引發render的再次渲染的。

運行中

初始化完成之後,組件將會進入到運行中狀態,運行中狀態我們將會遇到如下幾個函數:

componentWillReceiveProps(nextProps):props改變(父容器來更改或是redux),將會調用該函數。新的props將會作爲參數傳遞進來,老的props可以根據this.props來獲取。我們可以在該函數中對state作一些處理。注意:在該函數中更新state不會引起二次渲染。

boolean shouldComponentUpdate(object nextProps, object nextState):該函數傳遞過來兩個參數,新的state和新的props。state和props的改變都會調到該函數。該函數主要對傳遞過來的nextProps和nextState作判斷。如果返回true則重新渲染,如果返回false則不重新渲染。在某些特定條件下,我們可以根據傳遞過來的props和state來選擇更新或者不更新,從而提高效率。

componentWillUpdate(object nextProps, object nextState):與componentWillMount方法類似,組件上會接收到新的props或者state渲染之前,調用該方法。但是不可以在該方法中更新state和props。

render:跟初始化的時候功能一樣。

componentDidUpdate(object prevProps,object prevState):和初始化時期的componentDidMount類似,在render之後,真實DOM生成之後調用該函數。傳遞過來的是當前的props和state。在該函數中同樣可以使用this.getDOMNode()來拿到相應的DOM節點。如果你需要在運行中執行某些副操作,請在該函數中完成。

我們來演示componentWillReceiveProps的調用時機,對於頂層組件,我們添加一個文本及一個點擊事件:

按鈕點擊以後,我們將自身state的name屬性改變,並傳遞給SimpleApp(這裏的AppConnect就是SimpleApp),結果如下:

我們可以看到,第一次render,打印的是defaultProps傳過來的props。當按鈕點擊,頂層組件state改變,引發頂層組件重新渲染,父組件傳遞的name發生改變,componentWillReceiveProps被調用,繼而引發二次渲染。在第二次render的時候,打印出來的就是新傳遞過來的props。

銷燬

銷燬階段只有一個函數,很簡單

componentWillUnmount:組件DOM中移除的時候調用。在這裏進行一些相關的銷燬操作,比如定時器,監聽等等。

爲了加深記憶,我們把初始化和運行中所有的鉤子函數寫出來,讓大家看看最終的運行結果。

我們首先初始化組件,不執行任何操作,打印結果如圖所示:

當我們點擊按鈕,改變組件的props之後,打印結果如下:

我們給自身組件添加了一個點擊事件,點擊之後改變自身的state,如下:

點擊之後,再來看調用結果:

(疑問:當state發生改變的時候 會調用 componentWillReceiveProps嗎?還是直接從 shouldComponentUpdate開始的?)

這也印證了我們的結論

 

二.props和state

 

上面講完了生命週期,我們對props和state的不同點以及相同點作一個總結,加深大家理解。

相同點

1.不管是props還是state的改變,都會引發render的重新渲染。

2.都能由自身組件的相應初始化函數設定初始值。

不同點

1.初始值來源:state的初始值來自於自身的getInitalState(constructor)函數;props來自於父組件或者自身getDefaultProps(若key相同前者可覆蓋後者)。

2.修改方式:state只能在自身組件中setState,不能由父組件修改;props只能由父組件修改,不能在自身組件修改。

3.對子組件:props是一個父組件傳遞給子組件的數據流,這個數據流可以一直傳遞到子孫組件;state代表的是一個組件內部自身的狀態,只能在自身組件中存在。

 

 

 


作者:sidiWang
鏈接:https://www.jianshu.com/p/986bcbcd02aa
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯繫作者獲得授權並註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章