React 源碼解析 - 更新流程 renderRoot 渲染階段

往期回顧

React 源碼解析 React 的更新

React 源碼解析 - React 創(chuàng)建更新回顧和 React 的批量更新

React 源碼解析 - 調(diào)度模塊原理 - 實(shí)現(xiàn) requestIdleCallback ?

React 源碼解析 - reactScheduler 異步任務(wù)調(diào)度

renderRoot 入口

  • ReactFiberScheduler.js
function renderRoot(root: FiberRoot, isYieldy: boolean, isExpired: boolean) {
  // ...
  if ( // 將要執(zhí)行的任務(wù) root 和 expirationTime 和 nextRenderExpirationTime篮灼、nextRoot 預(yù)期的不一樣怀吻, 應(yīng)該是之前任務(wù)被高優(yōu)先級(jí)的任務(wù)打斷了。
    expirationTime !== nextRenderExpirationTime ||
    root !== nextRoot ||
    nextUnitOfWork === null // 更新結(jié)束 fiber 的 child佛玄,下一個(gè)節(jié)點(diǎn), 首次 = null
  ) {
  // 初始化的內(nèi)容
    resetStack(); // 重置
    nextRoot = root;
    nextRenderExpirationTime = expirationTime; // root.nextExpirationTimeToWorkOn;
    nextUnitOfWork = createWorkInProgress( // 拷貝了一份 fiber 對(duì)象操作
      nextRoot.current,
      null,
      nextRenderExpirationTime,
    );
    root.pendingCommitExpirationTime = NoWork; // 設(shè)置成 NoWork
  // ...
  }
// 開始進(jìn)入 workLoop 
  do {
    try {
      workLoop(isYieldy); // 進(jìn)行每個(gè)節(jié)點(diǎn)的更新
    } catch (thrownValue) {
      // ...
      break; // 遇到了某種錯(cuò)誤跳出
    }   while(true)

}

workLoop 中所有發(fā)生的錯(cuò)誤都會(huì)被 render 階段 catch雳刺,render 階段會(huì)根據(jù)捕獲的錯(cuò)誤具體內(nèi)容進(jìn)行相應(yīng)的操作

function workLoop(isYieldy) {
  if (!isYieldy) { // 不可中斷 Sync 和 超時(shí)任務(wù)不可中斷
    // Flush work without yielding
    // nextUnitOfWork 是 fiber 對(duì)象,為 null 已經(jīng)是 root 節(jié)點(diǎn) fiber return 的 null 了
    // 用于記錄render階段Fiber樹遍歷過程中下一個(gè)需要執(zhí)行的節(jié)點(diǎn)。在resetStack中分別被重置,他只會(huì)指向workInProgress
    while (nextUnitOfWork !== null) { // 不停的更新目锭,不為 null 就不停執(zhí)行 next 的 child 的更新
      nextUnitOfWork = performUnitOfWork(nextUnitOfWork); // 進(jìn)行更新
    }
  } else {
    // Flush asynchronous work until the deadline runs out of time.
    while (nextUnitOfWork !== null && !shouldYield()) { // 判斷 shouldYield = false 當(dāng)前時(shí)間片是否有時(shí)間更新
      nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    }
  }
}

workLoop 只是根據(jù)時(shí)間片是否有任務(wù)調(diào)用 performUnitOfWork 進(jìn)行更新, 只有當(dāng) nextUnitOfWork === null 時(shí)才代表任務(wù)已經(jīng)更新完了



performUnitOfWork 在 beginWork 中對(duì)當(dāng)前 fiber 進(jìn)行更新,更新到此 fiber 的最后時(shí)會(huì)去找兄弟節(jié)點(diǎn)纷捞,最后返回給 workLoop 中的 while(nextUnitOfWork) 中繼續(xù)執(zhí)行

beginWork

核心功能

  • 驗(yàn)證當(dāng)前 fiber 樹是否需要更新
  • 更新傳入的節(jié)點(diǎn)類型進(jìn)行對(duì)應(yīng)的更新
  • 更新后調(diào)和子節(jié)點(diǎn)

第一步驗(yàn)證當(dāng)前 fiber 樹是否需要更新

  • 比較當(dāng)前節(jié)點(diǎn) props 是否有變化
  • 檢查當(dāng)前節(jié)點(diǎn)是否有更新或是否比當(dāng)前 root 的更新優(yōu)先級(jí)大
  • 沒更新或優(yōu)先級(jí)低就跳過痢虹,bailoutOnAlreadyFinishedWork
  • bailoutOnAlreadyFinishedWork 可以判斷 current 是否有 child 更新


  • bailoutOnAlreadyFinishedWork 會(huì)判斷這個(gè) fiber 的子樹是否需要更新,如果有需要更新會(huì) clone 一份到 workInProgress.child 返回到 workLoop 的 nextUnitOfWork, 否則為 null


根據(jù) fiber 的 tag 類型進(jìn)行更新

進(jìn)行更新先把當(dāng)前 fiber 的 expirationTime 設(shè)置為 NoWork主儡,根據(jù) tag 進(jìn)行不同組件的更新


  • ClassComponent: class 組件
  • HostRoot: <div id="root" />
  • HostComponent: html 標(biāo)簽
  • HostText: 文本內(nèi)容
    ...

workInProgress 更新所用到的 fiber 對(duì)象屬性

  • type
    當(dāng)函數(shù)組件時(shí)是 function
    當(dāng)為 class 組件時(shí)就是 class 構(gòu)造函數(shù)
    當(dāng) dom 原生組件時(shí)就是標(biāo)簽 div 這種字符串
  • pendingProps
    fiber 更新帶來的新 props

更新函數(shù)會(huì)用到的參數(shù)

  • current
    workInProgress.alternate奖唯,指向當(dāng)前 fiber 沒更新的對(duì)象
  • Component
    workInProgress.type,此時(shí) fiber 節(jié)點(diǎn)組件的類型糜值,function丰捷,class坯墨,標(biāo)簽 字符串
  • nextProps
    workInProgress.pendingProps,此次更新帶來的新 props
  • renderExpirationTime
    fiberRoot.expirationTime病往,fiberRoot 上最大優(yōu)先級(jí)的值

FunctionComponent 更新

function updateFunctionComponent(
  current,
  workInProgress,
  Component,
  nextProps: any,
  renderExpirationTime,
) {
  // ... context 相關(guān)
  let nextChildren;
  // Component 組件方法捣染,這里就是我們聲明組件的方式 function(props, context) {}
  nextChildren = Component(nextProps, context); 
  // 把 nextChildren 這些 ReactElement 變成 Fiber 對(duì)象, 在 workInProgress.child 掛載 fiber  
  reconcileChildren( 
    current,
    workInProgress,
    nextChildren,
    renderExpirationTime,
  );
  return workInProgress.child;
}

reconcileChildren

核心點(diǎn)

  • 根據(jù) props.children 生成 fiber 子樹
  • 判斷 fiber 對(duì)象是否可以復(fù)用, 在第一次渲染就渲染了 fiber 子樹,state 變化可能會(huì)導(dǎo)致不能復(fù)用停巷,但是大部分是可以復(fù)用的
  • 列表根據(jù) key 優(yōu)化

根據(jù)首次渲染或更新渲染進(jìn)行操作

  • current === null 首次渲染, mountChildFibers
  • current !== null 更新渲染, reconcileChildFibers


  • mountChildFibers 和 reconcileChildFibers 都是由 ChildReconciler 返回的函數(shù)耍攘,區(qū)別只在參數(shù)不同
export const reconcileChildFibers = ChildReconciler(true);
export const mountChildFibers = ChildReconciler(false);

reconcileChildFibers

  • reconcileChildFibers 是 ChildReconciler 返回的最終函數(shù)
  • 先判斷 newChild 是不是 Fragment 節(jié)點(diǎn)
  • typeof newChild === object 是函數(shù)組件和 class 組件返回的 jsx - reconcileSingleElement
  • typeof newChild === string 是 textNode - reconcileSingleTextNode
  • 判斷 newChild 是個(gè)數(shù)組
  • 判斷是 iterator 函數(shù)
  • 都不符合拋錯(cuò)
  • 提醒組件沒有合法的返回值
  • 最后刪除所有的節(jié)點(diǎn) return deleteRemainingChildren(returnFiber: new, currentFirstChild: old);

placeSingleChild


更新渲染時(shí) placeSingleChild 會(huì)把新創(chuàng)建的 fiber 節(jié)點(diǎn)標(biāo)記為 Placement, 待到提交階段處理



其中 ReactElement, Portal, TextNode 三種類型的節(jié)點(diǎn)需要進(jìn)行處理x

reconcileSingleElement 更新 ReactElement

調(diào)和單個(gè)子節(jié)點(diǎn)

第一段邏輯,從原 fiber 節(jié)點(diǎn)的兄弟節(jié)點(diǎn)遍歷畔勤,比較 fiber 節(jié)點(diǎn)和 nextChilren key 值

  • 符合復(fù)用條件蕾各,標(biāo)記此 fiber 節(jié)點(diǎn)的所有兄弟節(jié)點(diǎn) effect 在提交階段刪除達(dá)到只復(fù)用干凈的這個(gè) fiber 節(jié)點(diǎn)的目的,返回這個(gè)可以復(fù)用的節(jié)點(diǎn)
  • 如果 key 相等庆揪,不符合復(fù)用條件直接跳出, 進(jìn)入第二段邏輯
  • 如果 key 不相等逐漸標(biāo)記刪除遍歷的 fiber 節(jié)點(diǎn), 進(jìn)入第二段邏輯
  • 這里調(diào)和單個(gè)子節(jié)點(diǎn), 如果 key 不存在為 null 我們也認(rèn)為他是相等的示损,判斷 type 和 elementType 來看他們是否一是個(gè)組件函數(shù)
  • deleteChild 標(biāo)記刪除
  • deleteRemainingChildren 刪除多余的兄弟節(jié)點(diǎn)

第二段邏輯,沒有可以復(fù)用的節(jié)點(diǎn)嚷硫,根據(jù) elment nextChildren 的類型創(chuàng)建 Fragment 或者 Element 類型的 fiber。

reconcileSingleTextNode 更新 textNode

  • currentFirstChild 原 fiber 節(jié)點(diǎn) child 是文本節(jié)點(diǎn)符合復(fù)用條件
  • currentFirstChild 不是文本節(jié)點(diǎn)始鱼,現(xiàn)在要更新為文本節(jié)點(diǎn)刪除后重新創(chuàng)建

useFiber 創(chuàng)建復(fù)用的節(jié)點(diǎn)


reconcileChildrenArray 調(diào)和數(shù)組 children

  • react 新老 children 對(duì)比的過程算法
  • 盡量減少節(jié)點(diǎn)的遍歷次數(shù)來達(dá)到判斷節(jié)點(diǎn)是否可復(fù)用的過程

第一次遍歷(優(yōu)化加速)

  • 找到新老節(jié)點(diǎn)中不能復(fù)用的節(jié)點(diǎn)才跳出
  • 判斷新老節(jié)點(diǎn)的 index
  • 判斷新老 key 是否相同來復(fù)用
  • 不能復(fù)用就 break 跳出當(dāng)前遍歷
  • 能復(fù)用就構(gòu)建鏈表結(jié)構(gòu)


updateSlot

  • 根據(jù) newChild 的類型和 oldChild.key 進(jìn)行判斷操作
  • 返回 null 表示后面都不能復(fù)用了直接跳出

textNode 文本節(jié)點(diǎn)

  • oldFiber 不是 textNode 還有 key 值仔掸,是在數(shù)組里的,新的 textNode 不能復(fù)用返回 null
  • oldFiber 不是 textNode 創(chuàng)建新的 textNode 否則直接更新 textNode 內(nèi)容

ReactElement 節(jié)點(diǎn)和 isArray 數(shù)組節(jié)點(diǎn)

  • ReactElement 時(shí) updateElement
  • Fragment 時(shí)與 ReactElement 的處理相似医清,復(fù)用處理的內(nèi)容為 newChild.props.children

break 或者遍歷完畢后的情況

  • newIdx === newChildren.length
  • 新的 children 已經(jīng)在 updateSlot 中創(chuàng)建新的對(duì)象了, 新數(shù)組操作完成了, 所有新節(jié)點(diǎn)都已經(jīng)創(chuàng)建
  • oldFiber === null
  • 老的已經(jīng)被復(fù)用完了, 新的節(jié)點(diǎn)還有部分沒有創(chuàng)建, 找到最后沒有能復(fù)用的節(jié)點(diǎn)了
  • 直接創(chuàng)建剩下的新節(jié)點(diǎn)構(gòu)建鏈表

情況一

  • 按新數(shù)組 newChildren.length 的長(zhǎng)度遍歷完了
  • 這時(shí) updateSlot 沒有返回 null起暮,所有節(jié)點(diǎn)都復(fù)用或新建的,都標(biāo)記好了位置
  • 這個(gè)情況是最快的会烙,如果 oldFiber 老節(jié)點(diǎn)還有沒遍歷完的就刪掉

情況二

  • 老的節(jié)點(diǎn)已經(jīng)被復(fù)用完了, 新的節(jié)點(diǎn)還有部分沒有創(chuàng)建, 遍歷到最后沒有能復(fù)用的節(jié)點(diǎn)了
  • newChildren 剩下的節(jié)點(diǎn)就直接創(chuàng)建负懦,同時(shí)進(jìn)行同樣的 place 標(biāo)記構(gòu)建鏈表結(jié)構(gòu)

核心通用操作,構(gòu)建 map 復(fù)用

  • newChildren 沒有創(chuàng)建完柏腻,oldFiber 又有兄弟節(jié)點(diǎn)纸厉,數(shù)組存在順序的變
  • 根據(jù)老節(jié)點(diǎn)的 key 或 index 構(gòu)建 map 對(duì)象
  • 遍歷剩下的 newChildren
  • 根據(jù) key 或 index 直接在 map 里找可以復(fù)用的對(duì)象或創(chuàng)建新的對(duì)象
  • 再構(gòu)建鏈表

更新 classComponent 組件

  • 首次渲染 instance === null
    • constructClassInstance 生成實(shí)例
    • mountClassInstance 掛載實(shí)例
  • 渲染被中斷 instance !== null, current === null
    • resumeMountClassInstance 復(fù)用實(shí)例但還是調(diào)用首次渲染的生命周期
  • 更新渲染 instance !== null, current !== null
    • updateClassInstance,調(diào)用 didUpdate 和 componentWillReceiveProp 生命周期
  • 都是復(fù)用或創(chuàng)建 instance五嫂,通過 processUpdateQueue 計(jì)算新的 state 賦值到 fiber workInProgress.memoizedState 和 instance 上面記錄
  • 最終執(zhí)行 finishClassComponent, 進(jìn)行錯(cuò)誤判斷的處理和判斷是否可以跳過更新的過程颗品,重新調(diào)和子節(jié)點(diǎn) reconcileChildren

首次渲染 class 組件

  • instance === null

constructClassInstance 創(chuàng)建實(shí)例

  • instance 賦值在 workInProgress.stateNode 上
function constructClassInstance(
  workInProgress: Fiber,
  ctor: any,
  props: any,
  renderExpirationTime: ExpirationTime,
): any {
  // ...
  // 從這里開始,ctor 就是 element.type 的 Compnent沃缘,這里生成 class 組件實(shí)例
  const instance = new ctor(props, context);
  const state = (workInProgress.memoizedState = // memoizedState 為實(shí)例的 state, 沒有就為 null
    instance.state !== null && instance.state !== undefined
      ? instance.state
      : null);
  adoptClassInstance(workInProgress, instance);
  // ...
  return instance;
}
  • 為 instance.updater 賦值 classComponentUpdater, 用于組件通過何種方式進(jìn)行 ReactDOM.render 和 setState 進(jìn)行更新
// 為實(shí)例確定 updater 對(duì)象
function adoptClassInstance(workInProgress: Fiber, instance: any): void {
  instance.updater = classComponentUpdater; // 給 class 組件實(shí)例的 updater 設(shè)置
  workInProgress.stateNode = instance; // instance 賦值給當(dāng)前 workInProgress.stateNode
  ReactInstanceMap.set(instance, workInProgress); // 給 instance._reactInternalFiber 賦值當(dāng)前的 fiber 對(duì)象
}

mountClassInstance 首次掛載實(shí)例

  • 初始化 class 組件創(chuàng)建 updateQueue 計(jì)算更新 state
  • 判斷和執(zhí)行 getDerivedStateFromProps, componentWillMount 生命周期躯枢,都會(huì)更新當(dāng)前 state
  • 可以看到 componentWillMount 完全可以進(jìn)行 setState,會(huì)創(chuàng)建 updateQueue 計(jì)算更新當(dāng)前 state
  • 最后標(biāo)記 componentDidMount 生命周期槐臀,待到提交階段更新完 dom 后執(zhí)行

processUpdateQueue 計(jì)算更新 state

  • updateQueue 的更新都是通過 baseState 計(jì)算的锄蹂,執(zhí)行 queue 的更新會(huì)檢查這次更新的優(yōu)先級(jí),優(yōu)先級(jí)低待到下次更新
  • 每個(gè) update 都會(huì)計(jì)算出當(dāng)前的 state 結(jié)果水慨,如果 setState 有第二個(gè)參數(shù) callback 會(huì)標(biāo)記 effect 待到提交階段執(zhí)行得糜,這樣 callback 就能得到準(zhǔn)確的 state
  • getStateFromUpdate 根據(jù) update.tag 計(jì)算 state 的結(jié)果敬扛,會(huì)判斷 setState 傳入的函數(shù)或?qū)ο髢煞N情況
    1 函數(shù)時(shí)會(huì)指定上下文,傳入 prevState, nextProps
    2 對(duì)象時(shí)就是最終要更新的 state 對(duì)象
    3 最后通過 Object.assign 生成新的 state 對(duì)象


resumeMountClassInstance 復(fù)用實(shí)例

  • 中斷后恢復(fù)的組件復(fù)用實(shí)例仍然按新組件掛載來執(zhí)行
  • 檢查得到 shouldUpdate掀亩,執(zhí)行 willMount 和標(biāo)記 didMount
  • shouldUpdate 由組件的 shouldComponentUpdate 判斷舔哪,pureComponent 會(huì)自動(dòng)比較 props

updateClassInstance 更新實(shí)例

  • 過程與 resumeMountClassInstance 相似, 不過執(zhí)行的是 willUpdate, 標(biāo)記 didUpdate, getSnapshotBeforeUpdate


finishClassComponent 完成 class 組件更新

沒錯(cuò)誤捕獲又不需要更新

  • 沒錯(cuò)誤捕獲也沒更新直接跳過
  • effect 的錯(cuò)誤標(biāo)記會(huì)在外側(cè) catch 中添加

捕獲錯(cuò)誤的操作

  • class 組件沒有 getDerivedStateFromError, nextChildren = null
  • class 組件有 getDerivedStateFromError 槽棍,直接執(zhí)行 instance.render() 獲得最新的 nextChildren, getDerivedStateFromError 在函數(shù)外 catch 到錯(cuò)誤并且執(zhí)行立即更新為正確的 state, 所以可以執(zhí)行 instance.render()
  • 沒捕獲錯(cuò)誤 執(zhí)行 instance.render()


最后執(zhí)行的 reconcileChildren

IndeterminateComponent 更新

  • fiber 剛創(chuàng)建的時(shí)候 fiberTag 都為 IndeterminateComponent 類型捉蚤,只有當(dāng) class 組件有 construct 才為 class 組件類型
  • 符合 class 組件條件按 class 組件更新
  • 否則就按函數(shù)組件類型更新
  • 只存在于首次更新的時(shí)候,只有首次更新的時(shí)候不確定 fiberTag 類型

更新 HostComponent 原生 dom 標(biāo)簽

  • 原生標(biāo)簽 小寫的 標(biāo)簽
  • 判斷標(biāo)簽內(nèi)容是不是純文本
  • 是純文本沒子節(jié)點(diǎn)炼七,不是純文本根據(jù)之前的 props 標(biāo)記更新
  • 跟 classCompnent 一樣有 makeRef 能使用 ref

updateHostComponent

  • dom 標(biāo)簽內(nèi)是純文本 nextChildren 為 null缆巧,直接渲染文本內(nèi)容
  • 原 props 是文本,現(xiàn)在換成節(jié)點(diǎn)標(biāo)記 effect 提交階段操作
  • 和 classComponent 一樣可以使用 ref 的原因是都有 markRef
  • 判斷 concurrentMode 異步組件是否有 hidden 屬性豌拙,異步組件 hidden 永不更新
  • 最后進(jìn)行 reconcileChildren

shouldSetTextContent

  • 特殊標(biāo)簽 textarea陕悬,option,noscript 直接渲染文本
  • props.children 為 string按傅,number 直接渲染
  • dangerouslySetInnerHTML 屬性 直接渲染

HostText 文本節(jié)點(diǎn)

updateHostText

文本內(nèi)容不需要構(gòu)建 fiber 結(jié)構(gòu)捉超,直接在提交階段更新就行了

function updateHostText(current, workInProgress) {
  if (current === null) {
    tryToClaimNextHydratableInstance(workInProgress);
  }
  // Nothing to do here. This is terminal. We'll do the completion step
  // immediately after.
  return null; // 文本沒有子節(jié)點(diǎn)不需要調(diào)和, 到 提交階段直接就更新了
}

ForwardRef 更新

  • 實(shí)現(xiàn)了 React.forwardRef((props, ref) => { 傳入了 ref }) 傳遞 ref 的功能

Mode 組件

  • React 提供的組件
  • <ConCurrentmode /> 標(biāo)簽
  • <StaticMode /> 標(biāo)簽
  • updateMode 執(zhí)行,const nextChildren = workInProgress.pendingProps.children;


Memo 組件

  • functionComponent 具有 pureComponent 功能
  • memo 組件 Component.type 就是 傳入的function組件唯绍, memo(function(props) {})
  • memo 組件的 props 都要作用于 function 組件內(nèi)
  • memo 組件意義不多只是進(jìn)行了一次包裹的比較
  • 創(chuàng)建的 child 沒有調(diào)和 reconcileChildren

初次渲染

  • 根據(jù) React.memo() 傳入的函數(shù)組件進(jìn)行判斷
  • SimpleFunctionComponent 的判斷, 沒有 defaulteProps, 不是構(gòu)造函數(shù), 簡(jiǎn)單函數(shù)組件只進(jìn)行淺比較
export function isSimpleFunctionComponent(type: any) {
  return (
    typeof type === 'function' &&
    !shouldConstruct(type) &&
    type.defaultProps === undefined
  );
}
  • updateSimpleMemoComponent

更新渲染

  • 優(yōu)先級(jí)低拼岳,進(jìn)行 PureComponent 功能的比較
  • 有必要更新直接創(chuàng)建節(jié)點(diǎn),構(gòu)建 fiber 樹

沒有調(diào)和 reconcileChildren


reconcileChildren 也是把 nextChildren 結(jié)果的 ReactElement 生成 fiber 后賦值給 workInprogress.child 上不過多了很多 類型的判斷, memo 組件有必要更新是直接創(chuàng)建后 賦值在 workInprogress.child 上了况芒,memo 組件編寫只會(huì)返回常規(guī)的 ReactElement 組件內(nèi)容

completeUnitOfWork

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

完成節(jié)點(diǎn)更新,重置 childExpirationTime

構(gòu)建 effect 鏈绝骚,供 commitRoot 提交階段使用

單側(cè)節(jié)點(diǎn)查找向上尋找節(jié)點(diǎn)

performUnitOfWork 遍歷 fiber 樹的順序

總結(jié)

  • renderRoot 階段毕籽,通過 fiberRoot.current 構(gòu)建 nextUnitOfWork
  • 在 workLoop 中對(duì) nextUnitOfWork 的每個(gè)節(jié)點(diǎn)進(jìn)行更新兽愤,從 fiberRoot 應(yīng)用的第一個(gè)子節(jié)點(diǎn)開始
  • workLoop 中 while 循環(huán) 執(zhí)行 nextUnitOfWork = performUnitOfWork(nextUnitOfWork)
  • performUnitOfWork 中以 nextUnitOfWork.alternate 和 nextUnitOfWork 做兩個(gè) fiber 的對(duì)照,通過 beginWork 依次遍歷復(fù)用和創(chuàng)建 fiber 構(gòu)建成新的 nextUnitOfWork.child ,再返回 workLoop 中的 performUnitOfWork
  • beginWork 根據(jù) tag 屬性判斷當(dāng)前 nextUnitOfWork 的節(jié)點(diǎn)類型與 alternate 對(duì)照來進(jìn)行對(duì)應(yīng)組件的復(fù)用更新胀屿,最后構(gòu)建成新的 fiber 樹膀藐,對(duì)節(jié)點(diǎn)上的操作進(jìn)行 effect 標(biāo)記
  • 當(dāng) beginWork 遍歷完單側(cè)子樹后會(huì)通過 completeUnitOfWork 構(gòu)建 effect 更新鏈奔浅,方便 commit 提交階段更新
  • completeUnitOfWork 在構(gòu)建完此側(cè)邊樹的 effect 鏈后, 向上尋找當(dāng)前 workInProgress 的 兄弟節(jié)點(diǎn)逛拱,繼續(xù) beginWork。
  • completeUnitOfWork 中如果找不到 workInProgress 的兄弟節(jié)點(diǎn)就繼續(xù)找父節(jié)點(diǎn)的兄弟節(jié)點(diǎn)滴须,直到找到 root 節(jié)點(diǎn)頂點(diǎn)返回 null舌狗,進(jìn)入 commitRoot 提交階段
  • renderRoot 通過前后 fiberRoot.current 的對(duì)照逐層的復(fù)用更新,構(gòu)建出一個(gè)新的 fiber 樹扔水,標(biāo)記節(jié)點(diǎn) effect 等到提交階段操作

參考文章

實(shí)現(xiàn) fiber 架構(gòu)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末痛侍,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌主届,老刑警劉巖赵哲,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異君丁,居然都是意外死亡枫夺,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門绘闷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來橡庞,“玉大人,你說我怎么就攤上這事印蔗“亲睿” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵华嘹,是天一觀的道長(zhǎng)吧趣。 經(jīng)常有香客問我,道長(zhǎng)耙厚,這世上最難降的妖魔是什么强挫? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮薛躬,結(jié)果婚禮上纠拔,老公的妹妹穿的比我還像新娘。我一直安慰自己泛豪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布侦鹏。 她就那樣靜靜地躺著诡曙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪略水。 梳的紋絲不亂的頭發(fā)上价卤,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音渊涝,去河邊找鬼慎璧。 笑死,一個(gè)胖子當(dāng)著我的面吹牛跨释,可吹牛的內(nèi)容都是我干的胸私。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼鳖谈,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼岁疼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起缆娃,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤捷绒,失蹤者是張志新(化名)和其女友劉穎瑰排,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體暖侨,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡椭住,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了字逗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片京郑。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖扳肛,靈堂內(nèi)的尸體忽然破棺而出傻挂,到底是詐尸還是另有隱情,我是刑警寧澤挖息,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布金拒,位于F島的核電站,受9級(jí)特大地震影響套腹,放射性物質(zhì)發(fā)生泄漏绪抛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一电禀、第九天 我趴在偏房一處隱蔽的房頂上張望幢码。 院中可真熱鬧,春花似錦尖飞、人聲如沸症副。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贞铣。三九已至,卻和暖如春沮明,著一層夾襖步出監(jiān)牢的瞬間辕坝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工荐健, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留酱畅,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓江场,卻偏偏與公主長(zhǎng)得像纺酸,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子址否,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • React 的更新 只解析到創(chuàng)建更新進(jìn)入調(diào)度器 創(chuàng)建更新的方式 初始渲染ReactDOM.renderReactD...
    coolheadedY閱讀 2,574評(píng)論 0 2
  • 說在前面 關(guān)于 react 的總結(jié)過去半年就一直碎碎念著要搞起來吁峻,各(wo)種(tai)原(lan)因(le)。心...
    陳嘻嘻啊閱讀 6,846評(píng)論 7 41
  • 一、React的工作原理 1用含、UI = f(data){} UI 就是界面 矮慕,這個(gè)界面就是函數(shù)執(zhí)行的結(jié)果,是按照函...
    it筱竹閱讀 1,186評(píng)論 0 4
  • 最近看了一本關(guān)于學(xué)習(xí)方法論的書啄骇,強(qiáng)調(diào)了記筆記和堅(jiān)持的重要性痴鳄。這幾天也剛好在學(xué)習(xí)React,所以我打算每天堅(jiān)持一篇R...
    gaoer1938閱讀 1,666評(píng)論 0 5
  • 前言 Facebook 的研發(fā)能力真是驚人缸夹, Fiber 架構(gòu)給 React 帶來了新視野的同時(shí)痪寻,將調(diào)度一詞介紹給...
    Floveluy閱讀 1,754評(píng)論 1 5