• <noscript id="ggggg"><dd id="ggggg"></dd></noscript>
    <small id="ggggg"></small> <sup id="ggggg"></sup>
    <noscript id="ggggg"><dd id="ggggg"></dd></noscript>
    <tfoot id="ggggg"></tfoot>
  • <nav id="ggggg"><cite id="ggggg"></cite></nav>
    <nav id="ggggg"></nav>
    成人黃色A片免费看三更小说,精品人妻av区波多野结衣,亚洲第一极品精品无码,欧美综合区自拍亚洲综合,久久99青青精品免费观看,中文字幕在线中字日韩 ,亚洲国产精品18久久久久久,黄色在线免费观看

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

    2019-6-12    seo達(dá)人

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

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

    另外有說的不對(duì)的地方還請(qǐng)幫我指正一下,先謝謝各位啦。

    目錄索引:

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

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

    生命周期

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

    調(diào)度

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

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

    React 生命周期詳解

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

     

     

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

    一些干貨

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

    嘗試?yán)斫?Fiber

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

    背景

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

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

    Fiber 到底做了什么事

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

    舉個(gè)潛水員的例子

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

     

     

     

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

     

     

     

    引入 Fiber 后帶來的三個(gè)階段

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

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

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

    其它生命周期鉤子

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

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

    更新機(jī)制

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

    setState()

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

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

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

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

    forceUpdate()

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

    舉個(gè)極端例子

    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í)行的,但是這里因?yàn)閟etState 寫在了 await 后面 // 所以情況相反。 復(fù)制代碼

    結(jié)語

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

    我的個(gè)人建議如下:

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




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

    日歷

    鏈接

    個(gè)人資料

    存檔

    主站蜘蛛池模板: 亚洲国产韩国精品在线| 91性爱视频| 久久99久久99精品免视看| 自拍偷自拍亚洲精品偷一| 在线亚洲欧美日韩精品专区| 岛国岛国免费v片在线观看| 深夜福利无码| 国产成人AV一区二区在线观看| 波多野结衣av在线观看| 久久精品国产亚洲AV高清y w| 在线视频一区二区免费| 国产成人77亚洲精品www| 在线观看精品自拍视频| 最新永久免费AV无码网站| 亚洲国产精品成人AV在线| 九九视屏| 日韩av中文字幕有码| 免费无码AV污污污在线观看| 精品无码国产AV一区二区三区| 博爱县| 97久人人做人人妻人人玩精品| 人妻无码Aⅴ中文系列| 91亚洲精品福利在线播放| 国内少妇高潮嗷嗷叫在线观看| 香蕉eeww99国产在线观看| 亚洲精品国产情侣AV在线| 国产精品无码久久AV不卡| 国产精品一区二区尿失禁| 本道无码一区二区久久激情| 女人被爽到高潮视频免费| 动漫精品中文字幕无码| 久久av无码精品人妻系列| 亚洲精品5555在线| 国产成人精品一区二免费网站| 99久久精品国产片| 天堂av亚洲一区二区| 中文岛国精品亚洲一区| 在线看片免费不卡人成视频| 韩国免费高清一级毛片性色| 国产最新一区二区三区天堂| 中文字幕一区二区三区免费看|