午夜无码人妻aⅴ大片色欲张津瑜,国产69久久久欧美黑人A片,色妺妺视频网,久久久久国产综合AV天堂

怎么從Context源碼實(shí)現(xiàn)React性能優(yōu)化

這篇文章主要介紹“怎么從Context源碼實(shí)現(xiàn)React性能優(yōu)化”的相關(guān)知識,小編通過實(shí)際案例向大家展示操作過程,操作方法簡單快捷,實(shí)用性強(qiáng),希望這篇“怎么從Context源碼實(shí)現(xiàn)React性能優(yōu)化”文章能幫助大家解決問題。

成都創(chuàng)新互聯(lián)不只是一家網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司;我們對營銷、技術(shù)、服務(wù)都有自己獨(dú)特見解,公司采取“創(chuàng)意+綜合+營銷”一體化的方式為您提供更專業(yè)的服務(wù)!我們經(jīng)歷的每一步也許不一定是最完美的,但每一步都有值得深思的意義。我們珍視每一份信任,關(guān)注我們的成都做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)質(zhì)量和服務(wù)品質(zhì),在得到用戶滿意的同時(shí),也能得到同行業(yè)的專業(yè)認(rèn)可,能夠?yàn)樾袠I(yè)創(chuàng)新發(fā)展助力。未來將繼續(xù)專注于技術(shù)創(chuàng)新,服務(wù)升級,滿足企業(yè)一站式成都全網(wǎng)營銷需求,讓再小的品牌網(wǎng)站制作也能產(chǎn)生價(jià)值!

組件render的時(shí)機(jī)

Context的實(shí)現(xiàn)與組件的render息息相關(guān)。在講解其實(shí)現(xiàn)前,我們先來了解render的時(shí)機(jī)。

換句話說,組件在什么時(shí)候render?

這個(gè)問題的答案,已經(jīng)在React組件到底什么時(shí)候render啊聊過。在這里再概括下:

在React中,每當(dāng)觸發(fā)更新(比如調(diào)用this.setState、useState),會為組件創(chuàng)建對應(yīng)的fiber節(jié)點(diǎn)。

fiber節(jié)點(diǎn)互相鏈接形成一棵Fiber樹。

有2種方式創(chuàng)建fiber節(jié)點(diǎn):

bailout,即復(fù)用前一次更新該組件對應(yīng)的fiber節(jié)點(diǎn)作為本次更新的fiber節(jié)點(diǎn)。

render,經(jīng)過diff算法后生成一個(gè)新fiber節(jié)點(diǎn)。組件的render(比如ClassComponent的render方法調(diào)用、FunctionComponent的執(zhí)行)就發(fā)生在這一步。

經(jīng)常有同學(xué)問:React每次更新都會重新生成一棵Fiber樹,性能不會差么?

React性能確實(shí)不算很棒。但如你所見,F(xiàn)iber樹生成過程中并不是所有組件都會render,有些滿足優(yōu)化條件的組件會走bailout邏輯。

比如,對于如下Demo:

function Son() {   console.log('child render!');   return <div>Son</div>; }   function Parent(props) {   const [count, setCount] = React.useState(0);    return (     <div onClick={() => {setCount(count + 1)}}>       count:{count}       {props.children}     </div>   ); }   function App() {   return (     <Parent>       <Son/>     </Parent>   ); }  const rootEl = document.querySelector("#root"); ReactDOM.render(<App/>, rootEl);

在線Demo地址[2]

點(diǎn)擊Parent組件的div子組件,觸發(fā)更新,但是child render!并不會打印。

這是因?yàn)镾on組件會進(jìn)入bailout邏輯。

bailout的條件

要進(jìn)入bailout邏輯,需同時(shí)滿足4個(gè)條件:

1.oldProps === newProps

即本次更新的props全等于上次更新的props。

注意這里是全等比較。

我們知道組件render會返回JSX,JSX是React.createElement的語法糖。

所以render的返回結(jié)果實(shí)際上是React.createElement的執(zhí)行結(jié)果,即一個(gè)包含props屬性的對象。

即使本次更新與上次更新props中每一項(xiàng)參數(shù)都沒有變化,但是本次更新是React.createElement的執(zhí)行結(jié)果,是一個(gè)全新的props引用,所以oldProps  !== newProps。

2.context value沒有變化

我們知道在當(dāng)前React版本中,同時(shí)存在新老兩種context,這里指老版本context。

3.workInProgress.type === current.type

更新前后fiber.type不變,比如div沒變?yōu)閜。

4.!includesSomeLane(renderLanes, updateLanes) ?

當(dāng)前fiber上是否存在更新,如果存在那么更新的優(yōu)先級是否和本次整棵Fiber樹調(diào)度的優(yōu)先級一致?

如果一致代表該組件上存在更新,需要走render邏輯。

bailout的優(yōu)化還不止如此。如果一棵fiber子樹所有節(jié)點(diǎn)都沒有更新,即使所有子孫fiber都走bailout邏輯,還是有遍歷的成本。

所以,在bailout中,會檢查該fiber的所有子孫fiber是否滿足條件4(該檢查時(shí)間復(fù)雜度O(1))。

如果所有子孫fiber本次都沒有更新需要執(zhí)行,則bailout會直接返回null。整棵子樹都被跳過。

不會bailout也不會render,就像不存在一樣。對應(yīng)的DOM不會產(chǎn)生任何變化。

老Context API的實(shí)現(xiàn)現(xiàn)

在我們大體了解了render的時(shí)機(jī)。有了這個(gè)概念,就能理解ContextAPI是如何實(shí)現(xiàn)的,以及為什么被重構(gòu)。

我們先看被廢棄的老ContextAPI的實(shí)現(xiàn)。

Fiber樹的生成過程是通過遍歷實(shí)現(xiàn)的可中斷遞歸,所以分為遞和歸2個(gè)階段。

Context對應(yīng)數(shù)據(jù)會保存在棧中。

在遞階段,Context不斷入棧。所以Concumer可以通過Context棧向上找到對應(yīng)的context value。

在歸階段,Context不斷出棧。

那么老ContextAPI為什么被廢棄呢?因?yàn)樗麤]法和shouldComponentUpdate或Memo等性能優(yōu)化手段配合。

shouldComponentUpdate的實(shí)現(xiàn)

要探究更深層的原因,我們需要了解shouldComponentUpdate的原理,后文簡稱其為SCU。

使用SCU是為了減少不必要的render,換句話說:讓本該render的組件走bailout邏輯。

剛才我們介紹了bailout需要滿足的條件。那么SCU是作用于這4個(gè)條件的哪個(gè)呢?

顯然是第一條:oldProps === newProps

當(dāng)使用shouldComponentUpdate,這個(gè)組件bailout的條件會產(chǎn)生變化:

-- oldProps === newProps

++ SCU === false

同理,使用PureComponenet和React.memo時(shí),bailout的條件也會產(chǎn)生變化:

-- oldProps === newProps

++ 淺比較oldProps與newsProps相等

回到老ContextAPI。

當(dāng)這些性能優(yōu)化手段:

使組件命中bailout邏輯

同時(shí)如果組件的子樹都滿足bailout的條件4

那么該fiber子樹不會再繼續(xù)遍歷生成。

換言之,不會再經(jīng)歷Context的入棧、出棧。

這種情況下,即使context value變化,子孫組件也沒法檢測到。

新Context API的實(shí)現(xiàn)

知道老ContextAPI的缺陷,我們再來看新ContextAPI是如何實(shí)現(xiàn)的。

當(dāng)通過:

ctx = React.createContext();

創(chuàng)建context實(shí)例后,需要使用Provider提供value,使用Consumer或useContext訂閱value。

如:

ctx = React.createContext();  const NumProvider = ({children}) => {   const [num, add] = useState(0);    return (     <Ctx.Provider value={num}>       <button onClick={() => add(num + 1)}>add</button>       {children}     </Ctx.Provider>   ) }

使用:

const Child = () => {   const {num} = useContext(Ctx);   return <p>{num}</p> }

當(dāng)遍歷組件生成對應(yīng)fiber時(shí),遍歷到Ctx.Provider組件,Ctx.Provider內(nèi)部會判斷context value是否變化。

如果context  value變化,Ctx.Provider內(nèi)部會執(zhí)行一次向下深度優(yōu)先遍歷子樹的操作,尋找與該P(yáng)rovider配套的Consumer。

在上文的例子中會最終找到useContext(Ctx)的Child組件對應(yīng)的fiber,并為該fiber觸發(fā)一次更新。

注意這里的實(shí)現(xiàn)非常巧妙:

一般更新是由組件調(diào)用觸發(fā)更新的方法產(chǎn)生。比如上文的NumProvider組件,點(diǎn)擊button調(diào)用add會觸發(fā)一次更新。

觸發(fā)更新的本質(zhì)是為了讓組件創(chuàng)建對應(yīng)fiber時(shí)不滿足bailout條件4:

!includesSomeLane(renderLanes, updateLanes) ?

從而進(jìn)入render邏輯。

在這里,Ctx.Provider中context value變化,Ctx.Provider向下找到消費(fèi)context  value的組件Child,為其fiber觸發(fā)一次更新。

則Child對應(yīng)fiber就不滿足條件4。

這就解決了老ContextAPI的問題:

由于Child對應(yīng)fiber不滿足條件4,所以從Ctx.Provider到Child,這棵子樹沒法滿足:

  • !! 子樹中所有子孫節(jié)點(diǎn)都滿足條件4

所以即使遍歷中途有組件進(jìn)入bailout邏輯,也不會返回null,即不會無視這棵子樹的遍歷。

最終遍歷進(jìn)行到Child,由于其不滿足條件4,會進(jìn)入render邏輯,調(diào)用組件對應(yīng)函數(shù)。

const Child = () => {   const {num} = useContext(Ctx);   return <p>{num}</p> }

在函數(shù)調(diào)用中會調(diào)用useContext從Context棧中找到對應(yīng)更新后的context value并返回。

關(guān)于“怎么從Context源碼實(shí)現(xiàn)React性能優(yōu)化”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,小編每天都會為大家更新不同的知識點(diǎn)。

分享標(biāo)題:怎么從Context源碼實(shí)現(xiàn)React性能優(yōu)化
鏈接地址:http://www.ekvhdxd.cn/article34/pjeese.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計(jì)、網(wǎng)站設(shè)計(jì)響應(yīng)式網(wǎng)站、移動(dòng)網(wǎng)站建設(shè)、網(wǎng)站制作微信公眾號

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

綿陽服務(wù)器托管