React-生命週期雜記

前言

自從React發佈Fiber以後,更新速度突飛猛進,而生命週期也隨之改變,雖然原有的一些生命週期函數面臨廢棄,但理解其背後更新的機制也是一種學習html

在這裏根據官方文檔以及社區上其餘優秀的文章進行一個對於生命週期的總結,大體上分爲如下三個模塊react

  1. 新老生命週期的區別
  2. 爲何數據獲取要在componentDidMount中進行
  3. 爲何要改變生命週期

新老生命週期的區別

新的生命週期增長了static getDerivedStateFromProps()以及getSnapshotBeforeUpdate(),廢棄了原有的componentWillMount()componentWillUpdate()以及componentWillReceiveProps()
分別如如下圖 安全

原生命週期: 框架

image

新生命週期(圖引用自React v16.3以後的組件生命週期函數): 異步

image

爲何數據獲取要在componentDidMount中進行

做者一開始也喜歡在React的willMount函數中進行異步獲取數據(認爲這能夠減小白屏的時間),後來發現其實應該在didMount中進行。函數

首先,分析一下二者請求數據的區別: 學習

componentWillMount獲取數據:優化

  1. 執行willMount函數,等待數據返回
  2. 執行render函數
  3. 執行didMount函數
  4. 數據返回, 執行render

didMount獲取數據:this

  1. 執行willMount函數
  2. 執行render函數
  3. 執行didMount函數, 等待數據返回
  4. 數據返回, 執行render

很明顯,在willMount中獲取數據,能夠節省時間(render函數和didMount函數的執行時間),可是爲何咱們還要在didMount中獲取數據spa

  1. 若是使用服務端渲染的話,willMount會在服務端和客戶端各自執行一次,這會致使請求兩次(接受不了~),而didMount只會在客戶端進行
  2. 在Fiber以後, 因爲任務可中斷,willMount可能會被執行屢次
  3. willMount會被廢棄,目前被標記爲不安全
  4. 節省的時間很是少,跟其餘的延遲狀況相比,這個優化可使用九牛一毛的形容(爲了這麼一點時間而一直不跟進技術的發展,得不償失),而且render函數是確定比異步數據到達先執行,白屏時間並不能減小

關於第一點,若是你想在服務端渲染時先完成數據的展現再一次性給用戶,官方的推薦作法是用constructor代替willMount

爲何要改變生命週期

從上面的生命週期的圖中能夠看出,被廢棄的三個函數都是在render以前,由於fiber的出現,極可能由於高優先級任務的出現而打斷現有任務致使它們會被執行屢次

另外的一個緣由則是,React想約束使用者,好的框架可以讓人不得已寫出容易維護和擴展的代碼,這一點又是從何談起,咱們能夠重新增長以及即將廢棄的生命週期分析入手

componentWillMoun

首先這個函數的功能徹底可使用componentDidMount和constructor來代替,異步獲取的數據的狀況上面已經說明了,而若是拋去異步獲取數據,其他的便是初始化而已,這些功能均可以在constructor中執行,除此以外,若是咱們在willMount中訂閱事件,但在服務端這並不會執行willUnMount事件,也就是說服務端會致使內存泄漏

因此componentWillMount徹底能夠不使用,但使用者有時候不免由於各類各樣的狀況(如做者犯渾)在componentWillMount中作一些操做,那麼React爲了約束開發者,乾脆就拋掉了這個API

componentWillReceiveProps

在老版本的 React 中,若是組件自身的某個 state 跟其 props 密切相關的話,一直都沒有一種很優雅的處理方式去更新 state,而是須要在 componentWillReceiveProps 中判斷先後兩個 props 是否相同,若是不一樣再將新的 props 更新到相應的 state 上去。這樣作一來會破壞 state 數據的單一數據源,致使組件狀態變得不可預測,另外一方面也會增長組件的重繪次數。相似的業務需求也有不少,如一個能夠橫向滑動的列表,當前高亮的 Tab 顯然隸屬於列表自身的狀態,但不少狀況下,業務需求會要求從外部跳轉至列表時,根據傳入的某個值,直接定位到某個 Tab。 本段引用自React v16.3 版本新生命週期函數淺析及升級方案

爲了解決這些問題,React引入了第一個新的生命週期

static getDerivedStateFromProps

能夠先看一下二者在使用上的區別:

原有的代碼
image

新的代碼
image

這樣看彷佛沒有什麼改變,特別是當咱們把this,tabChange也放在didUpdate中執行時(正確作法),徹底沒有不一樣,但這也是咱們一開始想說的,React經過API來約束開發者寫出更好的代碼,而新的使用方法有如下的優勢

  1. getDSFP是靜態方法,在這裏不能使用this,也就是一個純函數,開發者不能寫出反作用的代碼
  2. 開發者只能經過prevState而不是prevProps來作對比,保證了state和props之間的簡單關係以及不須要處理第一次渲染時prevProps爲空的狀況
  3. 基於第一點,將狀態變化(setState)和昂貴操做(tabChange)區分開,更加便於 render 和 commit 階段操做或者說優化。

componentWillUpdate

與 componentWillReceiveProps 相似,許多開發者也會在 componentWillUpdate 中根據 props 的變化去觸發一些回調。但不管是 componentWillReceiveProps 仍是 componentWillUpdate,都有可能在一次更新中被調用屢次,也就是說寫在這裏的回調函數也有可能會被調用屢次,這顯然是不可取的。與 componentDidMount 相似,componentDidUpdate 也不存在這樣的問題,一次更新中 componentDidUpdate 只會被調用一次,因此將原先寫在 componentWillUpdate 中的回調遷移至 componentDidUpdate 就能夠解決這個問題。 本段引用自React v16.3 版本新生命週期函數淺析及升級方案

另一種狀況則是咱們須要獲取DOM元素狀態,可是因爲在fiber中,render可打斷,可能在willMount中獲取到的元素狀態極可能與實際須要的不一樣,這個一般可使用第二個新增的生命函數的解決

getSnapshotBeforeUpdate

getSnapshotBeforeUpdate(prevProps, prevState) // 返回的值做爲componentDidUpdate的第三個參數

與willMount不一樣的是, getSnapshotBeforeUpdate會在最終肯定的render執行以前執行,也就是能保證其獲取到的元素狀態與didUpdate中獲取到的元素狀態相同,這裏官方提供了一段參考代碼:
image

總結

隨着React Fiber的落地,許多功能都將開始改變,但本質上是換湯不換藥,不少時候都是React爲了開發者寫出更好的代碼而作的改變,固然這也是React的厲害之處,經過框架來約束開發者!

相關文章
相關標籤/搜索