<thead id="kdfuf"><font id="kdfuf"></font></thead>
<samp id="kdfuf"></samp>
    <nav id="kdfuf"><strong id="kdfuf"></strong></nav>
      中文字幕无码一区二区三区在线,久久精品人人做人人爽,国产一级内射无挡观看,十八禁在线黄色网站,日韩欧美国产另类久久久精品 ,少妇人妻偷人精品一区二区,久久午夜视频,亚洲春色AⅤ无码专区

      重新學(xué)習(xí) React (一) 生命周期,F(xiàn)iber 調(diào)度和更新機制

      2019-6-12    seo達人

      如果您想訂閱本博客內(nèi)容,每天自動發(fā)到您的郵箱中, 請點這里

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

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

      目錄索引:

      什么是生命周期和調(diào)度?

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

      生命周期

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

      調(diào)度

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

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

      React 生命周期詳解

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

       

       

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

      一些干貨

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

      嘗試理解 Fiber

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

      背景

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

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

      Fiber 到底做了什么事

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

      舉個潛水員的例子

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

       

       

       

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

       

       

       

      引入 Fiber 后帶來的三個階段

      從生命周期那張圖片縱向來看,F(xiàn)iber 將整個生命周期分成了三個階段:

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

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

      其它生命周期鉤子

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

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

      更新機制

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

      setState()

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

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

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

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

      forceUpdate()

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

      舉個極端例子

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

      結(jié)語

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

      我的個人建議如下:

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




      藍藍設(shè)計www.tuitetiyu.cn )是一家專注而深入的界面設(shè)計公司,為期望卓越的國內(nèi)外企業(yè)提供卓越的UI界面設(shè)計、BS界面設(shè)計 、 cs界面設(shè)計 、 ipad界面設(shè)計 、 包裝設(shè)計 、 圖標定制 、 用戶體驗 、交互設(shè)計、 網(wǎng)站建設(shè) 平面設(shè)計服務(wù)

      日歷

      鏈接

      個人資料

      藍藍設(shè)計的小編 http://www.tuitetiyu.cn

      存檔

      主站蜘蛛池模板: 国内自产少妇自拍区免费| 国产精品无码一区二区三级| 甘肃省| 永久免费AV无码网站YY| 青青草国产精品日韩欧美| 天天躁夜夜躁狠狠是什么心态| 人妻少妇精品久久久久久自慰| 日日噜噜夜夜狠狠久久丁香五月 | 人妻激情乱人伦视频| 亚洲自偷自拍另类第一页| 久久黄色视频| 国产精亚洲无第一页| 国产一区二区视频免费| 欧美α片无限看在线观看免费| 2021最新亚洲高清无码| 国产美女精品自在线拍免费| 三上悠亚久久精品| 昭通市| 厨房与子乱在线观看| 日本高清免费中文字幕| 国产精品久久久久精品三级卜 | 久久综合网丁香五月| www国产亚洲精品久久久| а∨天堂一区一本到免费| 亚洲国产欧美日韩精品一区二区三区 | 一级毛片网| 国产精偷伦视频在线观看| 99久久久精品齐齐| 高清在线一区二区三区视频| 大陆一级毛片国语精品| 你是我的女人中文字幕高清| 67194熟妇在线直接进入| 久久国产欧美日韩精品图片| 中文乱码人妻系列一区| 欧美一级A一级a爱片免费免免| 国产精品成人VA久久久久一级毛片| 久久频这里精品99香蕉久网址| 日韩精品久久久久久福利| 色欲无码精品人妻系列AV| 爆乳护士一区二区三区在线播| 樱桃视频影院在线播放|