React-生命周期雜記

前言

自從React發布Fiber之后,更新速度日新月異,而生命周期也隨之改變,雖然原有的一些生命周期函數面臨廢棄,但理解其背后更新的機制也是一種學習

在這里根據官方文檔以及社區上其他優秀的文章進行一個對于生命周期的總結,大致上分為以下三個模塊

  1. 新老生命周期的區別
  2. 為什么數據獲取要在componentDidMount中進行
  3. 為什么要改變生命周期

新老生命周期的區別

新的生命周期增加了static getDerivedStateFromProps()以及getSnapshotBeforeUpdate(),廢棄了原有的componentWillMount()、componentWillUpdate()以及componentWillReceiveProps(),
分別如以下圖

原生命周期:

新生命周期(圖引用自React v16.3之后的組件生命周期函數):

為什么數據獲取要在componentDidMount中進行

作者一開始也喜歡在React的willMount函數中進行異步獲取數據(認為這可以減少白屏的時間),后來發現其實應該在didMount中進行。

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

componentWillMount獲取數據:

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

didMount獲取數據:

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

很明顯,在willMount中獲取數據,可以節省時間(render函數和didMount函數的執行時間),但是為什么我們還要在didMount中獲取數據

  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

可以先看一下兩者在使用上的區別:

原有的代碼

新的代碼

這樣看似乎沒有什么改變,特別是當我們把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中獲取到的元素狀態相同,這里官方提供了一段參考代碼:

總結

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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/275927.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/275927.shtml
英文地址,請注明出處:http://en.pswp.cn/news/275927.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

漫畫 | 一個NB互聯網項目的上線過程…

大家好,我是若川(點這里加我微信 ruochuan12,長期交流學習)。今天雖然是周六,但還是要上班,所以就推薦一篇比較輕松的漫畫。點擊下方卡片關注我、加個星標,或者查看源碼等系列文章。學習源碼整體…

stm32 中斷處理級別_STM32中斷優先級徹底講解

文章來源:http://blog.sina.com.cn/s/blog_4fed55ce0100j7nd.html一:綜述STM32 目前支持的中斷共為 84 個(16 個內核68 個外部), 16 級可編程中斷優先級的設置(僅使用中斷優先級設置 8bit 中的高 4 位)和16個搶占優先級(因為搶占優先級最多可…

胖子臉:庫珀·布萊克100年

In 16th century Europe, roman typefaces were the first to surpass blackletter as the preferred choice for expressing emphasis in print. True bold weight roman letters didn’t appear until the 19th century, which critics quickly coined “Fat Faces” due to …

C語言中的布爾值

C語言的布爾類型在C語言標準(C89)沒有定義布爾類型,所以C語言判斷真假時以0為假,非0為真。所以我們通常使用邏輯變量的做法: //定義一個int類型變量,當變量值為0時表示false,值為1時表示trueint flag;flag 0;//......…

用委托實現窗體間傳值

1.新建一個工程.在Form1中添加一個Label和一個Button.新建一個事件類,讓它有一個string 類型的屬性,用于傳值. 1 ///ReturnValueEventArgs.cs 2 using System; 3 using System.Collections.Generic; 4 using System.Text; 5 6 namespace test 7 { 8 public class Return…

c++ explicit關鍵字_聊一聊 C++的特性 explicit 匿名空間

聊一聊 C的特性 explicit && 匿名空間explicit關鍵字首先看一下explicit的作用:explicit 是避免構造函數的參數自動轉換為類對象的標識符,平時代碼中并不是經常用到,但是,有時候就是因為這個,會造成一定的BUG出…

谷歌瀏覽器那些有趣的隱藏功能

大家好,我是若川(點這里加我微信 ruochuan12,長期交流學習)。今天推薦一篇實用文章。文末有抽獎。點擊下方卡片關注我、加個星標,或者查看源碼等系列文章。學習源碼整體架構系列、年度總結、JS基礎系列很多小伙伴說還是…

AppDelegate的模塊化+瘦身

前言 關于iOS的模塊化,要追溯到16年接觸的BeeHive了,BeeHive將功能模塊化,以module的形式進行構建,以performSelector:的形式進行module的事件響應,以protocol的形式進行module間的通信。可以說思路非常清晰…

yii mysql_Yii2框架操作數據庫的方法分析【以mysql為例】

本文實例講述了Yii2框架操作數據庫的方法。分享給大家供大家參考,具體如下:準備數據庫DROP TABLE IF EXISTS pre_user;CREATE TABLE pre_user(id int(11) AUTO_INCREMENT PRIMARY KEY,username varchar(255) NOT NULL,password varchar(32) NOT NULL DEF…

C++接口注意

1. 用Record接口,要注意 Packed的區別 2. cdecl和stdcall的區別 3. C導出的函數建議用C格式stdcall導出,使用Def文件定義名稱 4. 用VS寫的API dll要注意是否引用了MFC的DLL,否則會使LoadLibrary失敗,并GetLastError后返回14001 Ap…

Vue 3.1.0 的 beta 版發布

大家好,我是若川(點這里加我微信 ruochuan12,長期交流學習)。昨晚尤大視頻號直播說到vue 3.1.0 beta版發布了,今天分享這篇文章。也有小伙伴可能注意到了昨晚我一直在送禮物。點擊下方卡片關注我、加個星標&#xff0c…

設計模式練習_設計練習是邪惡的

設計模式練習It was the final round of interviews. Or, so the candidate thought.這是采訪的最后一輪。 或者,所以候選人認為。 She’d spent all day interviewing in our office. As the final interviewer, I walked her out the building. She seemed confi…

morningcat2018 LearningDocs

2019獨角獸企業重金招聘Python工程師標準>>> LearningDocs 學習資料與文檔 JCP(Java Community Process ,Java社區進程 ) https://www.jcp.org/en/home/index JSR(Java Specification Requests,Java規范請求…

firefox下可惡的value

前幾天做項目 遇到這樣一個情況 document.getElementById("txtTest").value "111"; 這條語句在ff下和ie下都是好用的 但是用開發工具看html代碼 ie下顯示正常 ff下顯示的卻是修改之前的(實際上已經修改了,只是html沒有修改過來) 用js修改input…

據說 99% 的人不知道 vue-devtools 還能直接打開對應組件文件?本文原理揭秘

1. 前言你好,我是若川[1],微信搜索「若川視野」關注我,專注前端技術分享,一個愿景是幫助5年內前端開闊視野走向前列的公眾號。歡迎加我微信ruochuan12,長期交流學習。這是學習源碼整體架構系列 之 launch-editor 源碼&…

mysql 存儲 事務_MYSQL 可以在存儲過程里實現事務控制嗎

展開全部6.7 MySQL 事務與鎖定命令6.7.1 BEGIN/COMMIT/ROLLBACK 句法缺省的,MySQL 運行在 autocommit 模式。這就意味著,當你執行完一e69da5e887aa62616964757a686964616f31333361326265個更新時,MySQL 將立刻將更新存儲到磁盤上。如果你使用…

如何忽略證書繼續訪問_前5個最容易被忽視的可訪問性問題

如何忽略證書繼續訪問Accessibility is quickly becoming one of the most important aspects of the way we use the web, if not the most important. Just between 2017 and 2018, the number of federal court cases regarding web accessibility nearly tripled, signifyi…

《認清C++語言》のrandom_shuffle()和transform()算法

1&#xff09;STL中的函數random_shuffle()用來對一個元素序列進行重新排序&#xff08;隨機的&#xff09;&#xff0c;函數原型如下&#xff1a; template<class RandomAccessIterator> void random_shuffle( RandomAccessIterator _First, //指向序列首元素的迭代器 R…

作為前端開發,如何高效學習 TypeScript

大家好&#xff0c;我是若川。有朋友跟我說最近面試前端候選人&#xff0c;問到關于 JavaScript 的一些少見誤區問題&#xff0c;候選人很多都沒回答上來&#xff0c;他很詫異&#xff0c;一個從國際大廠出來的面試者&#xff0c;竟然對 JavaScript 的一些誤區問題都不了解。他…

figma下載_對于這10家公司,Figma是邁向新高度的起點

figma下載Hey everyone! In this post, we are highlighting 10 companies for which the use of Figma has become the starting point on the path to new heights. These are the use cases of problems and their solutions, where Figma played a decisive role.嘿大家&am…