国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

React源碼解析18(11)------ 實現(xiàn)多次setState的批處理

這篇具有很好參考價值的文章主要介紹了React源碼解析18(11)------ 實現(xiàn)多次setState的批處理。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

摘要

在React中,如果涉及到了多次setState,組件render幾次。setState是同步的還是異步的。這是一個很常見的面試題。

而本篇文章,就是主要實現(xiàn)React中,對于這部分的性能優(yōu)化,我們稱之為批處理。例如當(dāng)我有下面的JSX。

const root = document.querySelector('#root');

function App() {
  const [num, setNum] = useState(0)
  const click1 = () => {
    setNum(num + 1)
    setNum(num + 2)
    setNum(num + 3)
  }
  return jsx("div", {
    onClick: click1,
    children: num
  });
}

ReactDOM.createRoot(root).render(<App />)

對于當(dāng)前的點擊事件來說,只有最后的setNum(num + 3)是有效的。

但是在我們之前的實現(xiàn)中,對于這種連續(xù)三次setState,我們的代碼就要處理三次,就要經(jīng)過三次beginWork,completeWork,commitWork。

那我們能不能實現(xiàn)出一種方式,對于這種多次setState,最終之做最后一次處理。

1.修改update相關(guān)邏輯

目前,在我們的代碼里,能夠讓組件更新的方式,就是通過setState,觸發(fā)更新。而updateQueue就是用來保存更新的內(nèi)容。

function enqueueUpdate(updateQueue, update) {
  updateQueue.shared.pending = update
}

之前,在enqueueUpdate方法里,我們是直接進(jìn)行賦值的。這沒什么問題,因為之前每次賦值之后都會更新一下。

但是現(xiàn)在我們希望,最后只更新一次的話。我們就需要一個數(shù)據(jù)結(jié)構(gòu),可以保存多次更新的內(nèi)容。這里使用的是鏈表結(jié)構(gòu),但在真正的React源碼中,使用的是環(huán)形鏈表。

function enqueueUpdate(updateQueue, update) {
  // updateQueue.shared.pending = update

  let pending = updateQueue.shared.pending;
  if(pending === null) {
    updateQueue.shared.pending = update
  }else{
    while(pending.next != null) {
      pending = pending.next;
    }
    pending.next = update
    pending = pending.next;
  }
}

OK,修改完之后,我們調(diào)用了三次setState,那么updateQueue中保存的應(yīng)該是一個鏈表了。

在之前的processUpdateQueue方法里,也是直接更新就完了。但是現(xiàn)在updateQueue的結(jié)構(gòu)發(fā)生了變化,所以對于processUpdateQueue,更新邏輯也要改變。

function processUpdateQueue(baseState, pendingUpdate) {
  const result = {
    memoizedState: baseState
  }
  if(pendingUpdate.next === undefined) {
    const action = pendingUpdate.action;
    //setState(() => {}) 傳入方法
    if(typeof action === 'function'){
      result.memoizedState = action(baseState);
    }else {
      //setState()
      result.memoizedState = action;
    }
    return result
  }
  while(pendingUpdate != null) {
    const action = pendingUpdate.action;
    //setState(() => {}) 傳入方法
    if(typeof action === 'function'){
      baseState = action(baseState);
    }else {
      //setState()
      baseState = action;
    }
    pendingUpdate = pendingUpdate.next;
  }
  result.memoizedState = baseState;
  return result;
}

我們需要遍歷pending,將所有的更新內(nèi)容返回。

2.修改workLoop循環(huán)

我們想一下,之前觸發(fā)更新后,執(zhí)行的機(jī)制是什么樣子的。

  1. 更新updateQueue
  2. 拿到更新的updateQueue,掛載Hook上
  3. 執(zhí)行workLoop

也就是說,每次workLoop都只能拿到當(dāng)前更新的內(nèi)容。
如果我希望在第一次workLoop就可以拿到所有的更新內(nèi)容,并且取消后面的workLoop。

有什么方法呢?微任務(wù)?。。。?/p>

我們可以將執(zhí)行workLoop的過程放在微任務(wù)里,這樣執(zhí)行workLoop的時候,updateQueue的鏈表已經(jīng)生成。

同時我們用一個標(biāo)志位,取消后面的workLoop執(zhí)行。
當(dāng)workLoop執(zhí)行完成后,再將標(biāo)志位置反。

let isFinished = false;
export function syncWorkLoop(root,hostRootFilber) {
  if(isFinished) {
    return;
  }
  Promise.resolve(null).then(() => {
    wookLoop(root,hostRootFilber);
  })
  isFinished = true;`在這里插入代碼片`
}
const wookLoop = (root,hostRootFilber) => {
  //其他代碼。。。。。
  isFinished = false;
}

3.修改filberHook

最后,我們只要在filberHook中觸發(fā)的邏輯里,替換workLoop即可:

function disaptchState(filber, hook, action) {
  const update = createUpdate(action);
  enqueueUpdate(hook.updateQueue, update);
  workUpdateHook = hook;
  syncWorkLoop(filber.return.stateNode);
}

通過這種方式,當(dāng)我執(zhí)行多次setState,最終只會render一次。文章來源地址http://www.zghlxwxcb.cn/news/detail-666589.html

到了這里,關(guān)于React源碼解析18(11)------ 實現(xiàn)多次setState的批處理的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • React源碼解析18(5)------ 實現(xiàn)函數(shù)組件【修改beginWork和completeWork】

    React源碼解析18(5)------ 實現(xiàn)函數(shù)組件【修改beginWork和completeWork】

    經(jīng)過之前的幾篇文章,我們實現(xiàn)了基本的jsx,在頁面渲染的過程。但是如果是通過函數(shù)組件寫出來的組件,還是不能渲染到頁面上的。 所以這一篇,主要是對之前寫得方法進(jìn)行修改,從而能夠顯示函數(shù)組件,所以現(xiàn)在我們在index.js文件中,修改一下jsx的寫法。修改成函數(shù)組件

    2024年02月13日
    瀏覽(20)
  • React源碼解析18(1)------ React.createElement 和 jsx

    React源碼解析18(1)------ React.createElement 和 jsx

    我們知道在React17版本之前,我們在項目中是一定需要引入react的。 import React from “react” 即便我們有時候沒有使用到React,也需要引入。原因是什么呢? 在React項目中,如果我們使用了模板語法JSX,我們知道它要先經(jīng)過babel的轉(zhuǎn)譯。那babel會將JSX轉(zhuǎn)換成什么樣子的格式呢? 可

    2024年02月13日
    瀏覽(21)
  • React中的setState使用細(xì)節(jié)和原理解析

    React中的setState使用細(xì)節(jié)和原理解析

    前面我們有使用過setState的基本使用, 接下來我們對setState使用進(jìn)行詳細(xì)的介紹 使用setState的原因 開發(fā)中我們并不能直接通過修改state的值來讓界面發(fā)生更新 : 因為我們修改了state之后,希望React根據(jù)最新的State來重新渲染界面,但是 this.state 這種方式的修改React并不知道數(shù)據(jù)發(fā)

    2024年02月03日
    瀏覽(19)
  • React源碼解析18(2)------ FilberNode,F(xiàn)ilberRootNode結(jié)構(gòu)關(guān)系

    React源碼解析18(2)------ FilberNode,F(xiàn)ilberRootNode結(jié)構(gòu)關(guān)系

    在上一篇,我們實現(xiàn)了通過JSX轉(zhuǎn)換為ReactElement的方法,也看到了轉(zhuǎn)換后React元素的結(jié)構(gòu)。但是這個React元素,并不能很清楚的表達(dá)組件之間的關(guān)系,以及屬性的處理。 所以在React內(nèi)部,會將所有的React元素轉(zhuǎn)換為Filber樹。而這一章節(jié),主要就是簡單描述一下FilberNode的結(jié)構(gòu)。 首

    2024年02月13日
    瀏覽(20)
  • React源碼解析18(4)------ completeWork的工作流程【mount】

    React源碼解析18(4)------ completeWork的工作流程【mount】

    經(jīng)過上一章,我們得到的FilberNode已經(jīng)具有了child和return屬性。一顆Filber樹的結(jié)構(gòu)已經(jīng)展現(xiàn)出來了。 那我們最終是想在頁面渲染真實的DOM。所以我們現(xiàn)在要在completeWork里,構(gòu)建出一顆離屏的DOM樹。 之前在說FilberNode的屬性時,我們提到過一個屬性stateNode。它就是用來保存每個

    2024年02月13日
    瀏覽(26)
  • React源碼解析18(3)------ beginWork的工作流程【mount】

    React源碼解析18(3)------ beginWork的工作流程【mount】

    OK,經(jīng)過上一篇文章。我們調(diào)用了: 生成了FilberRootNode和HostRootFilber。 并且二者之間的對應(yīng)關(guān)系也已經(jīng)確定。 而下一步我們就需要調(diào)用render方法來講react元素掛載在root上: 所以我們現(xiàn)在要實現(xiàn)ReactDOM.createRoot中返回的render方法。 首先我們思考一下,在React中,除了通過上面的

    2024年02月13日
    瀏覽(26)
  • 前端React篇之React setState 調(diào)用的原理、React setState 調(diào)用之后發(fā)生了什么?是同步還是異步?

    在React中, setState 方法是用于更新組件狀態(tài)的重要方法。當(dāng) setState 被調(diào)用時,React會對組件進(jìn)行重新渲染,以反映狀態(tài)的變化。 具體的執(zhí)行過程如下: 調(diào)用 setState 入口函數(shù) :當(dāng)你在組件中調(diào)用 setState 方法時,實際上是調(diào)用了React組件的 setState 方法。這個方法在內(nèi)部充當(dāng)一

    2024年04月17日
    瀏覽(22)
  • 【React】組件生命周期、組件通信、setState

    【React】組件生命周期、組件通信、setState

    ? 組件化思想的應(yīng)用: ? ? 有了組件化的思想,我們在之后的開發(fā)中就要充分的利用它。 ? ? 盡可能的將頁面拆分成一個個小的、可復(fù)用的組件。 ? ? 這樣讓我們的代碼更加方便組織和管理,并且擴(kuò)展性也更強(qiáng)。 ? React的組件相對于Vue更加的靈活和多樣,按照不同的

    2024年01月20日
    瀏覽(20)
  • react中的setState是同步還是異步

    setState 只在合成事件和鉤子函數(shù)中是“異步”的,在原生事件和 setTimeout 中都是同步的。 合成事件:就是react 在組件中的onClick等都是屬于它自定義的合成事件 原生事件:比如通過addeventListener添加的,dom中的原生事件 setState的“異步”并不是說內(nèi)部由異步代碼實現(xiàn),其實本身

    2024年02月04日
    瀏覽(22)
  • React中setState是同步還是異步的

    setState()同步、異步總結(jié) 異步的情況: 由React控制的事件處理函數(shù),以及生命周期函數(shù)調(diào)用setState時表現(xiàn)為異步 。 大部分開發(fā)中用到的都是React封裝的事件,比如onChange、onClick、onTouchMove等(合成事件中),這些事件處理函數(shù)中的setState都是異步處理的。 注:上面的事件都是

    2024年02月11日
    瀏覽(17)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包