嫩草影院久久99_老司机午夜网站国内精品久久久久久久久_久久夜色精品国产_国产一级做a爰片久久毛片

重新學習 React (一) 生命周期,Fiber 調度和更新機制

2019-6-12    seo達人

如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

前幾天面試問道 react 的相關知識,對我打擊比較大,感覺對 react 認識非常膚淺,所以在這里重新梳理一下,想想之前沒有仔細思考過的東西。

另外有說的不對的地方還請幫我指正一下,先謝謝各位啦。

目錄索引:

什么是生命周期和調度?

React 有一套合理的運行機制去控制程序在指定的時刻該做什么事,當一個生命周期鉤子被觸發后,緊接著會有下一個鉤子,直到整個生命周期結束。

生命周期

生命周期代表著每個執行階段,比如組件初始化,更新完成,馬上要卸載等等,React 會在指定的時機執行相關的生命周期鉤子,使我們可以有機在程序運行中會插入自己的邏輯。

調度

我們寫代碼的時候往往會有很多組件以及他們的子組件,各自調用不同的生命周期,這時就要解決誰先誰后的問題,在 react v16 之前是采用了遞歸調用的方式一個一個執行,而在現在 v16 的版本中則采用了與之完全不同的處理(調度)方式,名叫 Fiber,這個東西 facebook 做了有兩年時間,實現非常復雜。

具體 Fiber 它是一個什么東西呢?不要著急,我們先從最基本的生命周期鉤子看起。

React 生命周期詳解

首先看一下 React V16.4 后的生命周期概況(圖片來源

 

 

  • 從橫向看,react 分為三個階段:
    • 創建時
      • constructor() - 類構造器初始化
      • static getDerivedStateFromProps() - 組件初始化時主動觸發
      • render() - 遞歸生成虛擬 DOM
      • componentDidMount() - 完成首次 DOM 渲染
    • 更新時
      • static getDerivedStateFromProps() - 每次 render() 之前執行
      • shouldComponentUpdate() - 校驗是否需要執行更新操作
      • render() - 遞歸生成虛擬 DOM
      • getSnapshotBeforeUpdate() - 在渲染真實 DOM 之前
      • componentDidUpdate() - 完成 DOM 渲染
    • 卸載時
      • componentWillUnmount() - 組件銷毀之前被直接調用

一些干貨

  • 有三種方式可以觸發 React 更新,props 發生改變,調用 setState() 和調用 forceUpdate()
  • static getDerivedStateFromProps() 這個鉤子會在每個更新操作之前(即使props沒有改變)執行一次,使用時應該保持謹慎。
  • componentDidMount() 和 componentDidUpdate() 執行的時機是差不多的,都在 render 之后,只不過前者只在首次渲染后執行,后者首次渲染不會執行
  • getSnapshotBeforeUpdate() 執行時可以獲得只讀的新 DOM 樹,此函數的返回值為 componentDidUpdate(prevProps, prevState, snapshot) 的第三個參數

嘗試理解 Fiber

關于 Fiber,強烈建議聽一下知乎上程墨Morgan的 live 《深入理解React v16 新功能》,這里潛水員的例子和圖片也是引用于此 live。

背景

我們知道 React 是通過遞歸的方式來渲染組件的,在 V16 版本之前的版本里,當一個狀態發生變更時,react 會從當前組件開始,依次遞歸調用所有的子組件生命周期鉤子,而且這個過程是同步執行的且無法中斷的,一旦有很深很深的組件嵌套,就會造成嚴重的頁面卡頓,影響用戶體驗。

React 在V16版本之前的版本里引入了 Fiber 這樣一個東西,它的英文涵義為纖維,在計算機領域它排在在進程和線程的后面,雖然 React 的 Fiber 和計算機調度里的概念不一樣,但是可以方便對比理解,我們大概可以想象到 Fiber 可能是一個比線程還短的時間片段。

Fiber 到底做了什么事

Fiber 把當前需要執行的任務分成一個個微任務,安排優先級,然后依次處理,每過一段時間(非常短,毫秒級)就會暫停當前的任務,查看有沒有優先級較高的任務,然后暫停(也可能會完全放棄)掉之前的執行結果,跳出到下一個微任務。同時 Fiber 還做了一些優化,可以保持住之前運行的結果以到達復用目的。

舉個潛水員的例子

我們可以把調度當成一個潛水員在海底尋寶,v16 之前是通過組件遞歸的方式進行尋寶,從父組件開始一層一層深入到最里面的子組件,也就是如下圖所示。

 

 

 

而替換成了 Fiber 后,海底變成的狹縫(簡單理解為遞歸變成了遍歷),潛水員會每隔一小段時間浮出水面,看看有沒有其他尋寶任務。注意此時沒有尋到寶藏的話,那么之前潛水的時間就浪費了。就這樣潛水員會一直下潛和冒泡,具體如下圖所示。

 

 

 

引入 Fiber 后帶來的三個階段

從生命周期那張圖片縱向來看,Fiber 將整個生命周期分成了三個階段:

  • render 階段
    • 由于 Fiber 會時不時跳出任務,然后重新執行,會導致該階段的生命周期調用多次的現象,所以 React V16 之前 componentWillMount()componentWillUpdate()componentWillReceiveProps() 的三個生命周期鉤子被加上了 UNSAFE 標記
    • 這個階段效率不一定會比之前同步遞歸來的快,因為會有任務跳出重做的性能損耗,但是從宏觀上看,它不斷執行了最高優先級(影響用戶使用體驗)的任務,所以用戶使用起來會比以前更加的流暢
    • 這個階段的生命周期鉤子可能會重復調用,建議只寫無副作用的代碼
  • pre-commit 階段
    • 該階段 DOM 已經形成,但還是只讀狀態
    • 這個階段組件狀態不會再改變
  • commit 階段
    • 此時的 DOM 可以進行操作
    • 這個階段組件已經完成更新,可以寫一些有副作用的代碼和添加其它更新操作。

簡而言之:以 render() 為界,之前執行的生命周期都有可能會打斷并多次調用,之后的生命周期是不可被打斷的且只會調用一次。所以盡量把副作用的代碼放在只會執行一次的 commit 階段。

其它生命周期鉤子

除了上面常用的鉤子,React 還提供了如下鉤子:

  • static getDerivedStateFromError() 在 render 階段執行,通過返回 state 更新組件狀態
  • componentDidCatch() 在 commit 階段執行,可以放一些有副作用的代碼

更新機制

理解了生命周期和三個執行階段,就可以比較容易理解組件狀態的更新機制了。

setState()

這個方法可以讓我們更新組件的 state 狀態。第一個參數可以是對象,也可以是 updater 函數,如果是函數,則會接受當前的 state 和 props 作為參數。第二個參數為函數,是在 commit 階段后執行,準確的說是在 componentDidUpdate() 后執行。

setState() 的更新過程是異步的(除非綁定在 DOM 事件中或寫在 setTimeout 里),而且會在最后合并所有的更新,如下:

Object.assign( previousState,
  {quantity: state.quantity + 1},
  {quantity: state.quantity + 1},
  ...
)
復制代碼

之所以設計成這樣,是為了避免在一次生命周期中出現多次的重渲染,影響頁面性能。

forceUpdate()

如果我們想強制刷新一個組件,可以直接調用該方法,調用時會直接執行 render() 這個函數而跳過 shouldComponentUpdate()

舉個極端例子

function wait() { return new Promise(resolve => {
    setTimeout(() => {
      resolve(); console.log("wait");
    }, 0);
  });
} //......省略組件創建 async componentDidMount() { await wait(); this.setState({ name: "new name" }); console.log("componentDidMount");
}

componentDidUpdate() { console.log("componentDidUpdate");
}

render() { console.log(this.state); return null } //......省略組件創建 // 輸出結果如下 // wait // {name: "new name"} // componentDidUpdate // componentDidMount // 注意 componentDidUpdate 的輸出位置,一般情況下 // componentDidUpdate 都是在componentDidMount 后面 // 執行的,但是這里因為setState 寫在了 await 后面 // 所以情況相反。 復制代碼

結語

了解 react 生命周期和更新機制確實有利于編寫代碼,特別是當代碼量越來越大時,錯用的 setState 或生命周期鉤子都可能埋下越來越多的雷,直到有一天無法維護。。。

我的個人建議如下:

  • 把副作用代碼通通放在 commit 階段,因為這個階段不會影響頁面渲染性能
  • 盡可能不要使用 forceUpdate() 方法,借用 Evan You 的一句話,如果你發現你自己需要在 Vue 中做一次強制更新,99.9% 的情況,是你在某個地方做錯了事
  • 只要調用了 setState() 就會進行 render(),無論 state 是否改變
  • 知道 setState() 更新的什么時候是同步的,什么時候是異步的,參見上文
  • 不要把 getDerivedStateFromProps() 當成是 UNSAFE_componentWillReceiveProps() 的替代品,因為 getDerivedStateFromProps() 會在每次 render() 之前執行,即使 props 沒有改變




藍藍設計www.sdgs6788.com )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 平面設計服務

日歷

鏈接

個人資料

藍藍設計的小編 http://www.sdgs6788.com

存檔

嫩草影院久久99_老司机午夜网站国内精品久久久久久久久_久久夜色精品国产_国产一级做a爰片久久毛片
<em id="09ttv"></em>
    <sup id="09ttv"><pre id="09ttv"></pre></sup>
    <dd id="09ttv"></dd>

        • 亚洲综合色视频| 久久99伊人| 欧美一区二区三区在线视频| av不卡在线看| 日韩天天综合| 亚洲最快最全在线视频| 最新69国产成人精品视频免费| 国产色视频一区| 国产欧美精品一区二区三区介绍 | 性欧美8khd高清极品| 亚洲美女尤物影院| 99re8这里有精品热视频免费| 亚洲精品综合| 亚洲一区二区三区四区五区午夜| 亚洲午夜羞羞片| 午夜在线a亚洲v天堂网2018| 欧美淫片网站| 噜噜噜躁狠狠躁狠狠精品视频 | 国产精品久久久久久模特| 欧美日韩天天操| 国产精品免费电影| 国产专区欧美精品| 亚洲二区视频在线| 亚洲免费久久| 午夜精品偷拍| 蜜臀av一级做a爰片久久| 亚洲国产欧美一区二区三区同亚洲 | 欧美日韩一区二区精品| 久久视频精品在线| 欧美女主播在线| 国产精品视频久久久| 国产亚洲一区二区三区在线观看| 在线免费观看日本欧美| 亚洲视频网在线直播| 久久精品一区二区三区不卡牛牛| 国产日产高清欧美一区二区三区| 国内精品美女在线观看| 亚洲精品中文字幕在线观看| 亚洲欧美国内爽妇网| 开心色5月久久精品| 日韩视频一区二区三区在线播放 | 亚洲一区二区三区高清| 久久综合九色99| 一区二区成人精品| 欧美成人国产| 国内精品久久久久久久影视蜜臀 | 久久久综合精品| 一本大道久久a久久综合婷婷| 久久久久一区二区三区四区| 国产精品久久国产三级国电话系列 | 亚洲精品一区二区三区av| 先锋影音网一区二区| 欧美理论在线| 亚洲国产中文字幕在线观看| 性欧美办公室18xxxxhd| 亚洲全黄一级网站| 久久久久久久久久久久久女国产乱 | 亚洲欧美国产精品va在线观看| 欧美福利视频在线观看| 久久久91精品国产| 国产一区二区高清视频| 亚洲欧美日韩国产综合精品二区| 欧美激情精品久久久久久久变态| 久久aⅴ国产欧美74aaa| 国产欧美日韩一区二区三区在线观看| av成人天堂| 亚洲精品影视| 欧美日韩国产区一| 99ri日韩精品视频| 亚洲国产1区| 美女91精品| 1000部国产精品成人观看| 国产精品成人国产乱一区| 一区二区三区免费网站| 亚洲精品一区在线观看| 欧美黄色小视频| 亚洲精品中文字幕有码专区| 亚洲国产精品久久久久婷婷老年| 先锋影音网一区二区| 国产亚洲精品7777| 久久精品亚洲精品国产欧美kt∨| 午夜精品国产精品大乳美女| 国产性色一区二区| 久热精品视频在线免费观看| 久久久亚洲午夜电影| 亚洲第一精品久久忘忧草社区| 欧美激情欧美激情在线五月| 欧美成人激情视频| 宅男66日本亚洲欧美视频| 正在播放亚洲一区| 国产性猛交xxxx免费看久久| 久久尤物视频| 另类亚洲自拍| 在线午夜精品自拍| 亚洲欧美日韩在线不卡| 国内精品亚洲| 亚洲欧洲在线播放| 国产精品一国产精品k频道56| 久久人人97超碰人人澡爱香蕉| 久久久久亚洲综合| 一区二区高清视频在线观看| 亚洲免费视频网站| 欧美aⅴ99久久黑人专区| 日韩一级黄色片| 国产精品久久久久av免费| 午夜一区在线| 久久亚洲二区| 国产精品99久久久久久久久| 亚洲欧美在线磁力| 亚洲福利一区| 亚洲国产精品久久久久秋霞不卡| 欧美日韩福利在线观看| 欧美在线免费视屏| 欧美国内亚洲| 久久久久久久久综合| 麻豆亚洲精品| 欧美一区=区| 欧美日韩在线观看一区二区三区| 久久久精品一区| 国产精品v欧美精品v日韩| 欧美电影在线观看完整版| 国产日韩精品在线| 中国女人久久久| 亚洲毛片在线观看.| 欧美在线啊v| 性欧美大战久久久久久久久| 欧美激情国产高清| 免费精品99久久国产综合精品| 欧美日精品一区视频| 欧美激情综合| 精品动漫3d一区二区三区免费| 一区二区三区日韩精品视频| 亚洲激情女人| 久久永久免费| 久热re这里精品视频在线6| 国产精品一级在线| 这里只有精品视频| 亚洲婷婷国产精品电影人久久| 麻豆九一精品爱看视频在线观看免费| 欧美中文字幕| 国产精品自在线| 中国女人久久久| 亚洲图片在线观看| 欧美日韩一区二区视频在线观看| 亚洲国产精品福利| 亚洲日本无吗高清不卡| 麻豆成人精品| 亚洲黄色在线观看| 99精品欧美一区二区三区综合在线 | 欧美成人午夜激情视频| 欧美大胆成人| 亚洲日本一区二区| 欧美日韩一级片在线观看| 亚洲综合色激情五月| 欧美在线视频一区二区三区| 海角社区69精品视频| 久久久免费精品视频| 欧美成人影音| 这里只有视频精品| 国产主播一区| 欧美激情视频在线播放| av成人天堂| 久久综合中文| 亚洲性人人天天夜夜摸| 国产永久精品大片wwwapp| 欧美成人dvd在线视频| 在线视频欧美日韩| 久久综合给合久久狠狠色| 亚洲精品视频在线| 国产精品亚洲美女av网站| 欧美综合国产精品久久丁香| 亚洲高清在线观看一区| 亚洲欧美日韩精品久久久| 国产一区二区在线免费观看| 另类图片综合电影| 亚洲无线一线二线三线区别av| 久久九九精品99国产精品| 亚洲国产日韩在线| 国产精品高清在线| 午夜视频久久久久久| 欧美.www| 性久久久久久久久| 欧美www视频| 亚洲欧美伊人| 久久噜噜亚洲综合| 亚洲女性裸体视频| 国产伦精品一区二区三区| 久久综合电影| 先锋影音一区二区三区| 噜噜噜91成人网| 亚洲精选在线观看| 欧美韩国日本一区| 欧美一区二区三区久久精品茉莉花| 美日韩在线观看| 亚洲天堂网在线观看| 亚洲理伦电影| 国模套图日韩精品一区二区| 欧美大片在线看免费观看| 亚洲欧洲日本专区| 久久久99久久精品女同性|