4.組件的生命周期

了解React生命周期,對我們理解React的工作過程很有幫助。所有的事物都有自己的生命過程,React組件也不例外,同樣有著自己的生命周期,而它的生命周期可能會經歷如下的三個過程:

  • 掛載過程
  • 更新過程
  • 銷毀過程

在經歷上面三個過程的時候,React庫會一次調用組件的一些成員函數,這些函數稱之為生命周期函數。因此,要定制一個react組件,實際上就是要定制這些生命周期函數。

掛載過程

在掛載過程中,當組件第一次被渲染時,會依次調用以下函數:

  • constructor
  • getInitialState
  • getDefaultProps
  • componentWillMount
  • render
  • componentDidMount
constructor

constructor也就是ES6語法中每個類的構造函數,而要創建一個組件類的實例,當然要調用對應的構造函數。但值得注意的是,不是每個React組件都需要定義自己的構造函數,使用構造函數一般都是以下兩個原因:

  1. 初始化state。因為組件中的任何函數都可能需要訪問state,因此在constructor中來初始化state是很好的選擇。
  2. 綁定成員函數的this。在es6中,累的每個成員函數在執行時的this并不是和類的實例所綁定的。而在鉤子凹函數中,this就是當前組件實例。所以,在此綁定this可以方便未來的調用。
getInitialState和getDefaultProps

已廢棄,不做討論

componentWillMount

在掛載過程中,componentWillMount會在render函數之前被調用。但通常來講我們不需要來定義componentWillMount,我們可以認為它所需要做的事情我們一般都在constructor中來做了。它所存在的意義更多的是為了與我們后面會提到的componentDidMount對稱。

render

render函數是React組件中最重要的函數。它并不是直接的去渲染動作,而是返回一個JSX描述的結構,然后最終由React來渲染過程。

對于render函數需要注意以下兩點:

  • 首先是我們在定義React組件的時候,可以忽略其他所有組件都不實現,但一定要實現render,因為所有React組件的父類對除了render函數之外的生命周期函數都有默認實現。
  • 其次render函數應該是一個純函數,應該完全根據this.state和this.props來決定返回的結果,而不應該產生任何副作用。因此,不應該在render中調用this.setState,這會引起狀態的變化。
componentDidMount

在render函數調用完之后componentDidMount函數并不會馬上被調用。它會在render函數返回的東西已經引發了渲染,組件已經被掛載到DOM書上時才會被調用。

前面提到的render函數知識返回JSX,并不負責直接的渲染,因此React庫需要把所有組件返回的結果全部集合起來,才可以知道如何產生對應的DOM修改。因此才會需要componentDidMount函數在render返回JSX,組件被渲染了才會調用來收尾。

它還有一個與componentWillMount函數不同的是,它只能在瀏覽器端被使用,而componentWillMount則可以使用在服務器端與瀏覽器端。這是由于只有瀏覽器端才會發生渲染的原因,服務器端可不會發生組件的掛載。

更新過程

當掛載過程結束之后,用戶們便可以看見我們的頁面了。但出于用戶體驗的角度來看,我們還需要提供更好的交互體驗,我們就需要組件可以隨著用戶操作來改變頁面內容,而props和state的修改,組件就會引發生更新過程。
更新過程包括以下生命周期函數:

  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate
  • componentDidUpdate
componentWillReceiveProps

這是在我們調用this.setState()方法之后,子組件收到新的props之后會觸發的函數。通過它的名字其實我們就可已看出,它知識will,而不會去更改props的值。

江湖上有謠傳,這個函數只有在組件的props函數發生改變時才會調用這個函數。其實不然。實際上,只要父組件的render函數被調用,在render函數里面被渲染的子組件都會經歷更新過程,componentWillReceiveProps函數也就會觸發。

而且,通過this.setState方法出發的更新過程也不會觸發該函數。這是由于這個函數適合更具新得props值來計算出是不是要更新內部狀態的state。而this.setState就是用于更新組件的內部狀態的,這會引起死循環。

shouldComponentUpdate

shouldComponentUpdate是一個很特殊的函數,它決定了一個組件什么時候不需要渲染。它是除了render函數之外最重要的函數了。

他們兩個也是React生命周期函數中唯二要求返回結果的函數。其中render函數的返回結果用于構造DOM對象,而它會返回同一個布爾值,默認會返回ture,但假如這個函數返回false的話,更新流程就會被跳過,render也不會繼續被觸發。

說shouldComponentUpdate重要就是由于只要利用的好,我們可以在這個函數中自定義一些判斷來跳過不需要被更新的組件,從而提升性能。

componentWillUpdate和componentDidUpdate

componentWillUpdate和componentDidUpdate分別會在render的
前后被觸發。

componentWillUpdate無法調用this.setState()可以理解為更新流程到這一步想要再更改state已經晚了。如果有需要我們可以在之前的componentWillReceiveProps中更新state,React會把改變合并到一個更新流程里進行。

componentDidUpdate則是另一個比較適合我們發起ajax請求的地方,在這個方法里我們還可以比較前后的props變化,再決定是否發起網絡請求。一個比較實際的使用場景是保存用戶輸入到服務器,用戶可能會來來回回修改輸入的內容,但假如我們判斷在修改前后數據最終沒有改變,就沒有必要發起不必要的網絡請求了。我們也可以通過它來來調用其他的UI庫。而且他也可以在服務器端來調用,因為服務器端中使用React基本不會經歷更新過程,所有也就無所謂了。

卸載過程

在卸載流程中,名為componentWillUnmount的函數會被觸發。在組件掛載之后,我們可能定義了一些計時器、綁定了事件監聽函數等等,在卸載流程的生命周期函數中,也是我們解綁這些函數的合適位置。

它的工作也一般和componentDidMount有關。比如,在componentDidMount中用非React的方法創造一些DOM元素,如果撒手不管就可能造成內存泄漏,這就需要componentWillUnmount函數來吧這些創造的DOM元素清理掉。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容