React 生命週期詳解

Tip:請不要死記生命週期的順序和做用,要理解 React 將這些生命週期暴露出來給開發者調用是由於開發者有使用這些生命週期的需求,經過這些生命週期,咱們能夠完成一些事情。

React 舊版生命週期

React 的生命週期圖如上所示,主要可分爲 初始化階段、掛載階段、更新階段、卸載階段。react

  • 初始化階段

發生在 constructor 中的內容,在 constructor 中進行 state、props 的初始化,在這個階段修改 state,不會執行更新階段的生命週期,能夠直接對 state 賦值。網絡

  • 掛載階段

對應的生命週期爲:dom

* 1.componentWillMount 
    發生在 render 函數以前,尚未掛載 Dom
* 2.render 
* 3.componentDidMount
    發生在 render 函數以後,已經掛載 Dom
  • 更新階段

更新階段分爲由 state 更新引發和 props 更新引發異步

* props
    * 1. componentWillReceiveProps(nextProps,nextState)
        這個生命週期主要爲咱們提供對 props 發生改變的監聽,若是你須要在 props 發生改變後,相應改變組件的一些 state。在這個方法中改變 state 不會二次渲染,而是直接合並 state。
    * 2. shouldComponentUpdate(nextProps,nextState)
        這個生命週期須要返回一個 Boolean 類型的值,判斷是否須要更新渲染組件,優化 react 應用的主要手段之一,當返回 false 就不會再向下執行生命週期了,在這個階段不能夠 setState(),會致使循環調用。
    * 3. componentWillUpdate(nextProps,nextState)
        這個生命週期主要是給咱們一個時機可以處理一些在 Dom 發生更新以前的事情,如得到 Dom 更新前某些元素的座標、大小等,在這個階段不能夠 setState(),會致使循環調用。
    **一直到這裏 this.props 和 this.state 都還未發生更新**
    * 4. render
        執行 render 函數。
    * 5. componentDidUpdate(prevProps, prevState) 
        在此時已經完成渲染,Dom 已經發生變化,State 已經發生更新,prevProps、prevState 均爲上一個狀態的值。
* state(具體同上)
    * 1. shouldComponentUpdate
    * 2. componentWillUpdate
    * 3. render
    * 4. componentDidUpdate
  • 卸載階段

對應的生命週期爲函數

* componentWillUnmount
componentWillUnmount 會在組件卸載及銷燬以前直接調用。在此方法中執行必要的清理操做,例如,清除 timer,取消網絡請求或清除在 componentDidMount  中建立的訂閱等。componentWillUnmount 中不該調用 setState,由於該組件將永遠不會從新渲染。組件實例卸載後,將永遠不會再掛載它。

根據上面的生命週期能夠理解所謂的 setState 是「異步」的並不是 setState 函數插入了新的宏任務或微任務,而是在進行到 componentDidUpdate 這個生命週期以前,React 都不會更新組件實例的 state 值。優化

引起問題: setState 在 setTimeout 和其餘事件回調中卻能夠同步更新( this.state 當即得到更新結果)是爲何呢?
答案: 在 React 中,若是是由 React 引起的事件處理(好比:onClick 引起的事件處理),調用 setState 不會同步更新 this.state,除此以外的 setState 調用會同步執行this.setState。 「除此以外」指的是:繞過 React 經過 addEventListener 直接添加的事件處理函數和 setTimeout/setInterval 產生的異步調用。
解釋: 每次 setState 產生新的state會依次被存入一個隊列,而後會根據isBathingUpdates 變量判斷是直接更新 this.state 仍是放進 dirtyComponent 裏回頭再說。isBatchingUpdates 默認是 false,也就表示 setState 會同步更新 this.state。可是,當 React 在調用事件處理函數以前就會調用 batchedUpdates,這個函數會把 isBatchingUpdates 修改成 true,形成的後果就是由 React 控制的事件處理過程 setState 不會同步更新 this.state。
解決方法: 當咱們想要依據上一個 state 的值來 setState 時,可使用函數式 setState。
function increment(state, props) {
  return {count: state.count + 1};
}
function incrementMultiple() {
  this.setState(increment);
  this.setState(increment);
  this.setState(increment);
}

React 新版生命週期

React 16 中刪除了以下三個生命週期。this

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

官方給出的解釋是 react 打算在17版本推出新的 Async Rendering,提出一種可被打斷的生命週期,而能夠被打斷的階段正是實際 dom 掛載以前的虛擬 dom 構建階段,也就是要被去掉的三個生命週期。
自己這三個生命週期所表達的含義是沒有問題的,但 react 官方認爲咱們(開發者)也許在這三個函數中編寫了有反作用的代碼,因此要替換掉這三個生命週期,由於這三個生命週期可能在一次 render 中被反覆調用屢次。spa

取代這三個生命週期的是兩個新生命週期code

  • static getDerivedStateFromProps(nextProps,nextState)component

    • 在 React 16.3.0 版本中:在組件實例化、接收到新的 props 時會被調用
    • 在 React 16.4.0 版本中:在組件實例化、接收到新的 props 、組件狀態更新時會被調用

該方法能夠返回一個對象,將會和 state 發生合併,且不會觸發 re-render。
這個生命週期主要爲咱們提供了一個能夠在組件實例化或 props、state 發生變化後根據 props 修改 state 的一個時機。用來替代舊的生命週期中的 componentWillMount、ComponentWillReceiveProps 。
由於是一個靜態方法,this 指向不是組件實例。

  • getSnapshotBeforeUpdate(prevProps,prevState)在 render 函數調用以後,實際的 Dom 渲染以前,在這個階段咱們能夠拿到上一個狀態 Dom 元素的座標、大小的等相關信息。用於替代舊的生命週期中的 componentWillUpdate。該函數的返回值將會做爲 componentDidUpdate 的第三個參數出現。
相關文章
相關標籤/搜索