React 源碼解析 - renderRoot 完成節(jié)點(diǎn)更新任務(wù)

completeUnitOfWork

當(dāng) beginWork 遍歷到 fiber 樹(shù)的單側(cè)最下方時(shí) next 為 null,這時(shí)候就會(huì)調(diào)用 completeUnitOfWork 完成節(jié)點(diǎn)并按遍歷順序設(shè)置新的 next 進(jìn)行操作

performUnitOfWork 遍歷 fiber 樹(shù)的順序

核心功能

  • 根據(jù)是否中斷調(diào)用不同的處理方法
  • 當(dāng)一側(cè)的子節(jié)點(diǎn)被 beginWork 更新組件完了執(zhí)行
  • beginWork 完成各個(gè)組件的 update,然后返回他的 child
  • 判斷是否有兄弟節(jié)點(diǎn)來(lái)執(zhí)行不同的操作
  • 完成節(jié)點(diǎn)之后復(fù) effect 鏈

completeUnitOfWork 沒(méi)有報(bào)錯(cuò)的處理流程

  • 當(dāng) workInProgress.effectTag 標(biāo)記的不是 Incomplete,沒(méi)有錯(cuò)誤捕獲
if ((workInProgress.effectTag & Incomplete) === NoEffect) { //.. }
  • completetWork 完成節(jié)點(diǎn)更新
  • resetChildExpirationTime 重置 childExpirationTime
  • 構(gòu)建 effect 鏈
  • 按照遍歷 fiber 樹(shù)的順序確定下 next 節(jié)點(diǎn)

resetChildExpirationTime 重置 workInProgress.childExpirationTime

  • 在 completeWork 完成節(jié)點(diǎn)更新后執(zhí)行
  • 重置的是 workInProgress 上的 childExpirationTime 屬性
  • 在當(dāng)前節(jié)點(diǎn)上找到子節(jié)點(diǎn)把所有子節(jié)點(diǎn)中不是 NoWork 的最早過(guò)期時(shí)間賦值給當(dāng)前節(jié)點(diǎn)的 childExpirationTime
  • childExpirationTime 來(lái)表示當(dāng)前節(jié)點(diǎn)所有子節(jié)點(diǎn)中最高的更新的優(yōu)先級(jí)

completeWork 完成節(jié)點(diǎn)更新

核心功能

  • pop 出各種 context 相關(guān)功能
  • 對(duì) HostComponent 進(jìn)行初始化
  • 初始化監(jiān)聽(tīng)事件
  • 對(duì)大部分 tag 不進(jìn)行操作或者只是 pop context
  • 只有 HostComponent, HostText, SuspenseComponent 有操作

HostComponent tag 的更新

tag 為 HostComponent 表示普通 dom 節(jié)點(diǎn),如: div

核心功能

  • diffProperties 計(jì)算需要更新的內(nèi)容
  • vdom 進(jìn)行對(duì)比是否真的要更新
  • 不同 dom property 處理方式不同
  • 根據(jù) current 原 fiber 節(jié)點(diǎn)和 workInProgress.stateNode 當(dāng)前 dom 判斷首次渲染還是更新渲染

初始更新

  • createInstance 根據(jù)當(dāng)前更新的節(jié)點(diǎn)創(chuàng)建新的 dom 對(duì)象并記錄創(chuàng)建的 fiber 和 props 屬性
  • appendAllChildren 構(gòu)建 dom 樹(shù),遍歷順序是從底向上只構(gòu)建第一層的 child, child.sibling
  • finalizeInitialChildren 初始化屬性,初始化事件監(jiān)聽(tīng)
  • markUpdate 標(biāo)記 effect = UPDATE,在 workInProgress.stateNode 上記錄 instance

createInstance 創(chuàng)建 dom

  • 創(chuàng)建 dom 節(jié)點(diǎn)
  • 在 dom 節(jié)點(diǎn)對(duì)象上記錄此次創(chuàng)建的 fiber 和 props 信息
  • createElement 創(chuàng)建 dom 對(duì)象

appendAllChildren 構(gòu)建 dom 樹(shù)

構(gòu)建 dom 樹(shù), 都是 append 第一層 child 和 child.sibling,不會(huì) append 嵌套的,嵌套的會(huì)在他自己是 workInProgress 時(shí) append

finalizeInitialChildren 初始化屬性,初始化事件監(jiān)聽(tīng)

  • 事件監(jiān)聽(tīng)初始化
  • 執(zhí)行 setInitialProperties
  • 返回 shouldAutoFocusHostComponent 告知是否需要 auto focus
  • switch 必要標(biāo)簽的操作
  • 綁定事件 trapBubbledEvent, 區(qū)分事件類型實(shí)現(xiàn)不同的事件綁定
  • input option select textarea 交互組件有不同的操作
  • 執(zhí)行 setInitialProperties 對(duì)應(yīng)不同標(biāo)簽綁定事件
  • 再執(zhí)行 setInitialDOMProperties
// ...
  setInitialDOMProperties(
    tag,
    domElement,
    rootContainerElement,
    props,
    isCustomComponentTag,
  );
  • setInitialDOMProperties 設(shè)置屬性和事件綁定
  • ensureListeningTo 事件綁定
  • listenTo 進(jìn)行綁定事件

HostComponent 更新 DOM 時(shí)進(jìn)行的 diff 判斷

updateHostComponent

diffProperties

  • 根據(jù)不同的節(jié)點(diǎn)做不同的操作
  • 生成 updatePayload 賦值給 workInProgress.updateQueue
  • 最后標(biāo)記 workInProgress.effect = UPDATE
  • 虛擬 dom 就是根據(jù) props 描述生成的 dom 對(duì)象
  • 根據(jù)不同標(biāo)簽節(jié)點(diǎn)提取新老 props 準(zhǔn)備比較
  • 第一次遍歷老 props 把要?jiǎng)h除的屬性都設(shè)置為 null
  • 第二次遍歷新 props
  • 比較 style 樣式對(duì)象, 最后(updatePayload = updatePayload || []).push(STYLE, styleUpdates);
  • 最后 return updatePayload: [k1,v1,k2,v2,k3,v3] 的屬性

completeWork 對(duì)于 HostText 的更新

  • 核心是 document.createTextNode

renderRoot 錯(cuò)誤處理

核心

  • 給報(bào)錯(cuò)的節(jié)點(diǎn)增加 Incomplete 副作用 effect
  • 給父鏈上具有 error boundary 的節(jié)點(diǎn)增加副作用
  • 創(chuàng)建錯(cuò)誤相關(guān)的更新

onUncaughtError

  • 致命錯(cuò)誤設(shè)置為 NoWork,不構(gòu)建 effect 鏈
  • nextFlushedRoot.expirationTime = NoWork; 取消當(dāng)前 root 的更新

throwException

  • 錯(cuò)誤處理 給報(bào)錯(cuò)節(jié)點(diǎn)組件 增加 Incomplete effect,
  • 清空?qǐng)?bào)錯(cuò)節(jié)點(diǎn)的 effect 鏈
  • suspened 異步組件拋出的 promise
  • 構(gòu)建錯(cuò)誤對(duì)象

throwException 處理錯(cuò)誤節(jié)點(diǎn)

  • 向上遍歷 class 組件找可以處理錯(cuò)誤的 class 組件生命周期
  • 一直找到 Root 節(jié)點(diǎn)執(zhí)行內(nèi)置錯(cuò)誤處理
  • 給能處理錯(cuò)誤的節(jié)點(diǎn)組件的 effect 都加了 ShouldCapture
  • 創(chuàng)建錯(cuò)誤更新,入 workInProgress.updateQueue 更新隊(duì)列來(lái)更新
  • getDerivedStateFromError 生命周期直接賦值在 update.payload 上
  • componentDidCatch 生命周期作為 callback 處理
  • createClassErrorUpdate 創(chuàng)建 class 組件處理錯(cuò)誤的 update
  • createRootErrorUpdate 創(chuàng)建 root 節(jié)點(diǎn)處理錯(cuò)誤的 update
  • 最后 enqueueCaptureUpdate,類似 enqueueUpdate 交給 react 更新

completeUnitOfWork 處理報(bào)錯(cuò)節(jié)點(diǎn)

  • 報(bào)錯(cuò)的節(jié)點(diǎn)直接進(jìn)入 completeUnitOfWork 完成
  • 不渲染子節(jié)點(diǎn)
  • 報(bào)錯(cuò)節(jié)點(diǎn)在 completeUnitOfWork 內(nèi)走 unwindWork 流程


unwindWork 的處理

  • 類似 completeWork 對(duì)不同組件進(jìn)行處理
  • 對(duì) shouldCapture 組件設(shè)置 DidCapture effect 副作用
  • 大部分沒(méi)動(dòng)作, 其余也多是 pop context
  • 只有 HostComponent, HostText, SuspenseComponent 有操作
  • 與 completeWork 最大的區(qū)別就是會(huì)判斷 ShouldCapture
  • throwException 處理錯(cuò)誤節(jié)點(diǎn)時(shí)給能處理錯(cuò)誤的節(jié)點(diǎn)組件的 effect 都加了 ShouldCapture


當(dāng)前報(bào)錯(cuò)組件能處理錯(cuò)誤重新標(biāo)記 effect

  • next 存在能處理錯(cuò)誤保留 HostEffectMask 以上的 effect
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容