React Advanced Notes
React Core Packages
Scheduler调度器: 调度任务的优先级, 高优任务优先进入Reconciler.Reconciler协调器:- 装载 
Renderer. - 接收 
ReactDOM和React模块 (用户代码) 发起的更新请求:ReactFiberReconciler.updateContainer.ReactFiberClassComponent.setState.ReactFiberHooks.dispatchAction.
 - 找出变化组件, 构建 Fiber Tree.
 
- 装载 
 Renderer渲染器:- 引导 
React应用启动 (e.gReactDOM.createRoot(rootNode).render(<App />)). - 实现 
HostConfig协议, 将变化的组件渲染到页面上. 
- 引导 
 
其中 Reconciler 构建 Fiber Tree 的过程被包装成一个回调函数, 传入 Scheduler 模块等待调度.
Scheduler 将回调函数进一步包装成任务对象, 放入多优先级调度的任务队列, 循环消费任务队列, 直至队列清空.
Scheduler Work Loop (任务调度循环) 负责调度 Task,
Reconciler Work Loop (Fiber 构造循环) 负责实现 Task.
React runtime main logic:
- Updates: 
Add/Delete/Mutationupdates fromUser Code. - Registration:
Reconcilerreceive updates request fromUser Code.Schedulerregister newTask.
 - Execution:
SchedulerconsumeTaskinTaskQueuein work loop.ReconcilerexecuteTaskwork.Fiber构造循环: constructFibertree.commitRoot: renderFibertree withRenderer.
 - 任务调度循环与 
Fiber构造循环相互配合可实现可中断渲染:- 渲染中断 (
Reconciler.renderRootConcurrent().shouldYield()):- 存在更高优先级任务 (Priority Scheduling).
 - 当前帧没有剩余时间 (Time Slicing).
 
 - 渲染恢复 (
Scheduler.workLoop()): 将callback()返回的任务放入任务队列, 继续进行调度直至清空任务队列. 
 - 渲染中断 (
 
React Virtual DOM
- Reduce rendering times with reconciliation algorithm,
improving rendering efficiency:
Declarative UI performance = Diff performance + DOM performance,
Virtual DOM主要是为了最小化 Diff 性能消耗. - Cross platform code.
 - Functional programming without details on DOM manipulation.
 - Virtual DOM 很多时候都不是最优的操作, 但它具有普适性, 在效率与可维护性之间达到平衡.
 - SnabbDOM: virtual DOM library focus on modularity and performance.
 
React Core Workflow
Create RootContainer
Legacy Root
- react-dom/src/client/ReactDOMLegacy:
- render.
 - legacyRenderSubtreeIntoContainer.
 - legacyCreateRootFromDOMContainer.
 
 - react-reconciler/src/ReactFiberReconciler:
- createContainer.
 
 - react-dom/src/client/ReactDOMComponentTree:
- markContainerAsRoot.
 
 - react-reconciler/src/ReactFiberRoot:
- createFiberRoot.
 
 - react-reconciler/src/ReactFiber:
- createHostRootFiber.
 
 - react-reconciler/src/ReactUpdateQueue:
- initializeUpdateQueue.
 
 - react-dom/src/events/DOMPluginEventSystem:
- listenToAllSupportedEvents: 事件统一在 rootContainer 上处理 dispatchDiscreteEvent.
 
 
Concurrent Root
- react-dom/src/client/ReactDOMRoot:
- createRoot.
 
 - react-reconciler/src/ReactFiberReconciler:
- createContainer.
 
 - react-dom/src/client/ReactDOMComponentTree:
- markContainerAsRoot.
 
 - react-reconciler/src/ReactFiberRoot:
- createFiberRoot.
 
 - react-reconciler/src/ReactFiber:
- createHostRootFiber.
 
 - react-reconciler/src/ReactUpdateQueue:
- initializeUpdateQueue.
 
 - react-dom/src/events/DOMPluginEventSystem:
- listenToAllSupportedEvents: 事件统一在 rootContainer 上处理 dispatchDiscreteEvent.
 
 ReactDOMRoot.render(<App />).
Update RootContainer
- react-dom/src/client/ReactDOMLegacy:
- render.
 - legacyRenderSubtreeIntoContainer.
 
 - react-dom/src/client/ReactDOMRoot:
- render.
 
 - react-reconciler/src/ReactFiberReconciler:
- updateContainer.
 
 - react-reconciler/src/ReactUpdateQueue:
- createUpdate.
 - enqueueUpdate.
 
 - react-reconciler/src/ReactFiberWorkLoop:
- scheduleUpdateOnFiber.
 - ensureRootIsScheduled.
 
 - react-reconciler/src/ReactFiberSyncTaskQueue:
- flushSyncCallbacks.
 
 - react-reconciler/src/ReactFiberWorkLoop:
- performSyncWorkOnRoot.
 - renderRootSync.
 - workLoopSync.
 - performUnitOfWork.
 
 - react-reconciler/src/ReactFiberBeginWork:
- beginWork.
 - updateHostRoot/updateXXXComponent.
 ReactDOMComponent.createElement.- reconcileChildren.
 
 - react-reconciler/src/ReactChildFiber:
- reconcileChildFibers.
 
 - react-reconciler/src/ReactFiberWorkLoop:
- completeUnitOfWork.
 
 - react-reconciler/src/ReactFiberCompleteWork
- completeWork.
 
 - react-reconciler/src/ReactFiberWorkLoop:
- commitRoot.
 
 - react-dom/src/client/ReactDOMHostConfig:
- appendChildToContainer.
 - finalizeInitialChildren.
 
 - react-dom/src/client/ReactDOMComponent:
- setInitialProperties: 设置初始化属性, 处理特殊元素和事件.
 
 
// Legacy Mode
import type { ReactElement } from 'react'
import Reconciler from './reconciler'
import type { Container } from './types'
const Renderer = {
  render: (
    element: ReactElement,
    container: Container | null,
    callback?: Function
  ): void => {
    if (container) {
      const root = Reconciler.createContainer(container, 0, false, null)
      Reconciler.updateContainer(element, root, null)
    }
  },
}
export default Renderer
// Modern Mode
import type { ReactElement } from 'react'
import Reconciler from './reconciler'
import type { Container, OpaqueRoot } from './types'
const Renderer = {
  createRoot: (
    container: Container | null,
    callback?: Function
  ): OpaqueRoot => {
    if (container) {
      const root = Reconciler.createContainer(container, 0, false, null)
      root.render = function (element: ReactElement) {
        Reconciler.updateContainer(element, this, null)
      }
      return root
    }
  },
}
export default Renderer
ReactComponent SetState
- react-dom/src/events/ReactDOMEventListener:
- dispatchDiscreteEvent.
 
 - react/src/ReactBaseClasses:
- setState.
 
 - react-reconciler/src/ReactFiberClassComponent:
- enqueueSetState.
 
 - react-reconciler/src/ReactUpdateQueue:
- createUpdate.
 - enqueueUpdate.
 
 - react-reconciler/src/ReactFiberWorkLoop:
- scheduleUpdateOnFiber.
 - discreteUpdates.
 
 - react-reconciler/src/ReactFiberSyncTaskQueue:
- flushSyncCallbacks.
 
 - react-reconciler/src/ReactFiberWorkLoop:
- performSyncWorkOnRoot.
 - workLoopSync.
 - performUnitOfWork.
 
 - react-reconciler/src/ReactFiberBeginWork:
- beginWork.
 - updateXXXComponent.
 - reconcileChildren.
 
 - react-reconciler/src/ReactChildFiber:
- reconcileChildFibers.
 
 - react-reconciler/src/ReactFiberWorkLoop:
- completeUnitOfWork.
 
 - react-reconciler/src/ReactFiberCompleteWork
- completeWork.
 
 - react-reconciler/src/ReactFiberWorkLoop:
- commitRoot.
 - commitMutationEffects.
 
 - react-reconciler/src/ReactFiberCommitWork:
- commitWork.
 
 - react-dom/src/client/ReactDOMHostConfig:
- commitUpdate.
 
 - react-dom/src/client/ReactDOMComponentTree:
- updateFiberProps.
 
 - react-dom/src/client/ReactDOMComponent:
- updateProperties: Apply the diff.
 
 
ClassComponent Update
- react-reconciler/src/ReactFiberWorkLoop:
- performSyncWorkOnRoot.
 - workLoopSync.
 - performUnitOfWork.
 
 - react-reconciler/src/ReactFiberBeginWork:
- beginWork
 - updateClassComponent.
 
 - react-reconciler/src/ReactFiberClassComponent:
- updateClassInstance.
 
 - react-reconciler/src/ReactFiberBeginWork:
- finishClassComponent.
 - instance.render (User defined Component).
 - reconcileChildren.
 
 - react-reconciler/src/ReactChildFiber:
- reconcileChildFibers.
 
 
FunctionComponent Update
- react-reconciler/src/ReactFiberWorkLoop:
- performSyncWorkOnRoot.
 - workLoopSync.
 - performUnitOfWork.
 
 - react-reconciler/src/ReactFiberBeginWork:
- beginWork.
 - updateFunctionComponent.
 
 - react-reconciler/src/ReactFiberHooks:
- renderWithHooks.
 - FunctionComponent() (User defined Function).
 - Hooks: useXXX -> mountXXX -> updateXXX.
 
 - react-reconciler/src/ReactFiberBeginWork:
- reconcileChildren.
 
 - react-reconciler/src/ReactChildFiber:
- reconcileChildFibers.
 
 
React Scheduler
Work loop in scheduler focus on Task Scheduling,
not only including Reconciler.performSyncWorkOnRoot/Reconciler.performConcurrentWorkOnRoot,
but also for non-react tasks
(meaning Scheduler module can work standalone without React).
Scheduler Priority
React 16, unstable concurrent mode with
Priorities:
- ImmediatePriority: 立即执行优先级, 级别最高, 
expirationTime = -1. - UserBlockingPriority: 用户阻塞优先级, 
expirationTime = 250. - NormalPriority: 正常优先级, 
expirationTime = 5000. - LowPriority: 低优先级, 
expirationTime = 10000. - IdlePriority: 可闲置优先级, 
expirationTime = maxSigned31BitInt. 
React 17, stable concurrent mode with
Lanes:
export type Lanes = number
export type Lane = number
export const TotalLanes = 31
export const NoLanes: Lanes = /*                        */ 0b0000000000000000000000000000000
export const NoLane: Lane = /*                          */ 0b0000000000000000000000000000000
export const SyncLane: Lane = /*                        */ 0b0000000000000000000000000000001
export const InputContinuousHydrationLane: Lane = /*    */ 0b0000000000000000000000000000010
export const InputContinuousLane: Lanes = /*            */ 0b0000000000000000000000000000100
export const DefaultHydrationLane: Lane = /*            */ 0b0000000000000000000000000001000
export const DefaultLane: Lanes = /*                    */ 0b0000000000000000000000000010000
const TransitionHydrationLane: Lane = /*                */ 0b0000000000000000000000000100000
const TransitionLanes: Lanes = /*                       */ 0b0000000001111111111111111000000
const TransitionLane1: Lane = /*                        */ 0b0000000000000000000000001000000
const TransitionLane2: Lane = /*                        */ 0b0000000000000000000000010000000
const TransitionLane3: Lane = /*                        */ 0b0000000000000000000000100000000
const TransitionLane4: Lane = /*                        */ 0b0000000000000000000001000000000
const TransitionLane5: Lane = /*                        */ 0b0000000000000000000010000000000
const TransitionLane6: Lane = /*                        */ 0b0000000000000000000100000000000
const TransitionLane7: Lane = /*                        */ 0b0000000000000000001000000000000
const TransitionLane8: Lane = /*                        */ 0b0000000000000000010000000000000
const TransitionLane9: Lane = /*                        */ 0b0000000000000000100000000000000
const TransitionLane10: Lane = /*                       */ 0b0000000000000001000000000000000
const TransitionLane11: Lane = /*                       */ 0b0000000000000010000000000000000
const TransitionLane12: Lane = /*                       */ 0b0000000000000100000000000000000
const TransitionLane13: Lane = /*                       */ 0b0000000000001000000000000000000
const TransitionLane14: Lane = /*                       */ 0b0000000000010000000000000000000
const TransitionLane15: Lane = /*                       */ 0b0000000000100000000000000000000
const TransitionLane16: Lane = /*                       */ 0b0000000001000000000000000000000
const RetryLanes: Lanes = /*                            */ 0b0000111110000000000000000000000
const RetryLane1: Lane = /*                             */ 0b0000000010000000000000000000000
const RetryLane2: Lane = /*                             */ 0b0000000100000000000000000000000
const RetryLane3: Lane = /*                             */ 0b0000001000000000000000000000000
const RetryLane4: Lane = /*                             */ 0b0000010000000000000000000000000
const RetryLane5: Lane = /*                             */ 0b0000100000000000000000000000000
export const SomeRetryLane: Lane = RetryLane1
export const SelectiveHydrationLane: Lane = /*          */ 0b0001000000000000000000000000000
const NonIdleLanes = /*                                 */ 0b0001111111111111111111111111111
export const IdleHydrationLane: Lane = /*               */ 0b0010000000000000000000000000000
export const IdleLane: Lanes = /*                       */ 0b0100000000000000000000000000000
export const OffscreenLane: Lane = /*                   */ 0b1000000000000000000000000000000
Scheduler Workflow
Scheduler main workflow:
scheduleCallback(callback)
-> push(queue, newTask) (Wrap callback into task)
(For delayed task -> requestHostTimeout(handleTimeout, delayTime))
-> requestHostCallback(flushWork)
-> messageChannelPort.postMessage(null)
-> performWorkUntilDeadline()
-> flushWork(hasTimeRemaining, currentTime):
-> workLoop(hasTimeRemaining, currentTime):
将 Reconciler 的工作 (Callback) 包装成 Task 组成 Task Queue, 按照时间分片机制, 不断地消费 Task Queue.
对于延时任务 (Delayed Task), 会将其先放入 Timer Queue, 等待延时完成后再将其放入 Task Queue.
Scheduler Time Slicing
// 时间切片周期, 默认是 5ms.
// 如果一个 task 运行超过该周期, 下一个 task 执行前, 会把控制权归还浏览器.
const yieldInterval = 5
const maxYieldInterval = 300
let deadline = 0 // currentTime + yieldInterval.
let needsPaint = false
let isMessageLoopRunning = false
let scheduledHostCallback = null
const channel = new MessageChannel()
const port = channel.port2
channel.port1.onmessage = performWorkUntilDeadline
const scheduling = navigator.scheduling
const getCurrentTime = performance.now
// 请求回调:
function requestHostCallback(callback) {
  // 1. 保存 callback.
  scheduledHostCallback = callback
  if (!isMessageLoopRunning) {
    isMessageLoopRunning = true
    // 2. 通过 MessageChannel 发送消息.
    port.postMessage(null)
  }
}
// 取消回调:
function cancelHostCallback() {
  scheduledHostCallback = null
}
function requestHostTimeout(callback, ms) {
  taskTimeoutID = setTimeout(() => {
    callback(getCurrentTime())
  }, ms)
}
function cancelHostTimeout() {
  clearTimeout(taskTimeoutID)
  taskTimeoutID = -1
}
// 是否让出主线程 (time slice):
function shouldYieldToHost() {
  const currentTime = getCurrentTime()
  if (currentTime >= deadline) {
    if (needsPaint || scheduling.isInputPending()) {
      // There is either a pending paint or a pending input.
      return true
    }
    // There's no pending input.
    // Only yield if we've reached the max yield interval.
    return currentTime >= maxYieldInterval
  } else {
    // There's still time left in the frame.
    return false
  }
}
// 请求绘制:
function requestPaint() {
  needsPaint = true
}
// 实际回调函数处理:
function performWorkUntilDeadline() {
  if (scheduledHostCallback !== null) {
    // 1. 设置 currentTime 与 deadline.
    const currentTime = getCurrentTime()
    deadline = currentTime + yieldInterval
    const hasTimeRemaining = true
    try {
      // 2. 执行回调, 返回是否有还有剩余任务.
      const hasMoreWork = scheduledHostCallback(hasTimeRemaining, currentTime)
      if (!hasMoreWork) {
        // 没有剩余任务, 退出.
        isMessageLoopRunning = false
        scheduledHostCallback = null
      } else {
        port.postMessage(null) // 有剩余任务, 发起新的调度.
      }
    } catch (error) {
      port.postMessage(null) // 如有异常, 重新发起调度.
      throw error
    }
  } else {
    isMessageLoopRunning = false
  }
  needsPaint = false // Reset.
}
Scheduler Task Queue
Task queue is MinHeap, storing Tasks.
const newTask = {
  id: taskIdCounter++,
  callback, // Work from reconciler.
  priorityLevel,
  startTime,
  expirationTime,
  sortIndex: -1, // MinHeap queue indexing.
}
function scheduleCallback(priorityLevel, callback, options) {
  const currentTime = getCurrentTime()
  const startTime = currentTime
  const expirationTime = startTime + timeout[priorityLevel] // -1/250/5000/10000/MAX_INT.
  const newTask = {
    id: taskIdCounter++,
    callback,
    priorityLevel,
    startTime,
    expirationTime,
    sortIndex: -1,
  }
  if (startTime > currentTime) {
    // Delayed task.
    newTask.sortIndex = startTime
    push(timerQueue, newTask)
    // All tasks are delayed, and this is the task with the earliest delay.
    if (peek(taskQueue) === null && newTask === peek(timerQueue)) {
      if (isHostTimeoutScheduled) {
        // Cancel an existing timeout.
        cancelHostTimeout()
      } else {
        isHostTimeoutScheduled = true
      }
      // Schedule a timeout.
      requestHostTimeout(handleTimeout, startTime - currentTime)
    }
  } else {
    // Normal task.
    newTask.sortIndex = expirationTime
    push(taskQueue, newTask)
    if (!isHostCallbackScheduled && !isPerformingWork) {
      isHostCallbackScheduled = true
      requestHostCallback(flushWork)
    }
  }
  return newTask
}
function handleTimeout(currentTime) {
  isHostTimeoutScheduled = false
  advanceTimers(currentTime)
  if (!isHostCallbackScheduled) {
    if (peek(taskQueue) !== null) {
      isHostCallbackScheduled = true
      requestHostCallback(flushWork)
    } else {
      const firstTimer = peek(timerQueue)
      if (firstTimer !== null)
        requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime)
    }
  }
}
Scheduler Work Loop
当 callback() 返回函数时, 表明产生连续回调 (e.g 出现更高优先任务/时间分片用完, 渲染中断),
需将返回的函数再次放入任务队列, 继续进行调度直至清空任务队列 (渲染恢复).
function flushWork(hasTimeRemaining, initialTime) {
  // We'll need a host callback the next time work is scheduled.
  isHostCallbackScheduled = false
  if (isHostTimeoutScheduled) {
    // We scheduled a timeout but it's no longer needed. Cancel it.
    isHostTimeoutScheduled = false
    cancelHostTimeout()
  }
  isPerformingWork = true // Lock.
  const previousPriorityLevel = currentPriorityLevel
  try {
    return workLoop(hasTimeRemaining, initialTime)
  } finally {
    // Restore context.
    currentTask = null
    currentPriorityLevel = previousPriorityLevel
    isPerformingWork = false
  }
}
function workLoop(hasTimeRemaining, initialTime) {
  let currentTime = initialTime
  advanceTimers(currentTime)
  currentTask = peek(taskQueue)
  while (currentTask !== null) {
    if (
      currentTask.expirationTime > currentTime
      && (!hasTimeRemaining || shouldYieldToHost())
    ) {
      // This currentTask hasn't expired, and we've reached the deadline.
      break
    }
    const callback = currentTask.callback
    if (typeof callback === 'function') {
      currentTask.callback = null
      currentPriorityLevel = currentTask.priorityLevel
      const didUserCallbackTimeout = currentTask.expirationTime <= currentTime
      const continuationCallback = callback(didUserCallbackTimeout)
      currentTime = getCurrentTime()
      if (typeof continuationCallback === 'function') {
        // 产生了连续回调 (如 Fiber树太大, 出现了中断渲染), 保留 currentTask.
        currentTask.callback = continuationCallback
      } else {
        if (currentTask === peek(taskQueue))
          pop(taskQueue)
      }
      advanceTimers(currentTime)
    } else {
      // 如果任务被取消 (currentTask.callback = null), 将其移出队列.
      pop(taskQueue)
    }
    currentTask = peek(taskQueue)
  }
  // Return whether there's additional work.
  if (currentTask !== null) {
    return true
  } else {
    const firstTimer = peek(timerQueue)
    // 存在延时任务, 继续进行调度.
    if (firstTimer !== null)
      requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime)
    return false
  }
}
React Fiber
React Fiber 的目标是提高其在动画、布局和手势等领域的适用性:
- 它的主要特性是 
Incremental Rendering: 将渲染任务拆分为小的任务 块并将任务分配到多个帧上的能力. - Ability to pause and resume rendering.
 - Ability to prioritize updates.
 - Ability to work on multiple tasks concurrently.
 
React Fiber Type
Fiber definition:
- Component type.
 - Current props and state.
 - Pointers to parent, sibling, and child components,
 - Pointer to DOM/class instance.
 - Other internal metadata to track rendering process.
 
export interface Fiber {
  tag: WorkTag
  key: string | null
  elementType: any
  type: any // Tag/Class/Function.
  stateNode: any // DOM/class instance.
  ref: (((handle: mixed) => void) & { _stringRef: ?string }) | RefObject | null
  // Singly Linked List Tree Structure.
  return: Fiber | null // DFS parent Fiber node.
  child: Fiber | null
  sibling: Fiber | null
  index: number
  // Props and state for output.
  pendingProps: any
  memoizedProps: any
  updateQueue: mixed // Updates from diff(pendingProps, memoizedProps).
  memoizedState: any
  // Context API.
  dependencies: Dependencies | null // (Contexts, Events) dependencies.
  mode: TypeOfMode // NoMode/BlockingMode/ConcurrentMode bit.
  // Effects.
  flags: Flags
  subtreeFlags: Flags
  deletions: Array<Fiber> | null
  nextEffect: Fiber | null // Next effect Fiber node.
  firstEffect: Fiber | null // First effect Fiber node.
  lastEffect: Fiber | null // Last effect Fiber node.
  // Priority.
  lanes: Lanes
  childLanes: Lanes
  alternate: Fiber | null // `current` Fiber and `workInpProgress` Fiber.
  // Performance statistics for React DevTool.
  actualDuration?: number
  actualStartTime?: number
  selfBaseDuration?: number
  treeBaseDuration?: number
}
React Fiber Work Tag
常见的 Fiber 类型:
- HostComponent: HTML native tag.
 - ClassComponent.
 - FunctionComponent.
 
type WorkTag =
  | 'FunctionComponent'
  | 'ClassComponent'
  | 'IndeterminateComponent'
  | 'HostRoot'
  | 'HostPortal'
  | 'HostComponent'
  | 'HostText'
  | 'Fragment'
  | 'Mode'
  | 'ContextConsumer'
  | 'ContextProvider'
  | 'ForwardRef'
  | 'Profiler'
  | 'SuspenseComponent'
  | 'MemoComponent'
  | 'SimpleMemoComponent'
  | 'LazyComponent'
  | 'IncompleteClassComponent'
  | 'DehydratedFragment'
  | 'SuspenseListComponent'
  | 'FundamentalComponent'
  | 'ScopeComponent'
  | 'Block'
  | 'OffscreenComponent'
  | 'LegacyHiddenComponent'
React Fiber Mode
React 运行模式:
所有 Fiber.mode 保持一致 (包括 FiberRoot).
type TypeOfMode = number
const NoMode = /*                         */ 0b000000
const ConcurrentMode = /*                 */ 0b000001
const ProfileMode = /*                    */ 0b000010
const DebugTracingMode = /*               */ 0b000100
const StrictLegacyMode = /*               */ 0b001000
const StrictEffectsMode = /*              */ 0b010000
const ConcurrentUpdatesByDefaultMode = /* */ 0b100000
React Fiber Effects
- Insert DOM elements: 
Placementtag. - Update DOM elements: 
Updatetag. - Delete DOM elements: 
Deletiontag. - Update Ref property: 
Reftag. useEffectcallback:got Passivetag.useEffect(fn):MountandUpdatelifecycle.useEffect(fn, []):Mountlifecycle.useEffect(fn, [deps]):Mountlifecycle andUpdatelifecycle withdepschanged.
React create effects when Render stage,
then update effects to real DOM when Commit stage.
常见的 Effect 标志位:
type Flags = number
const NoFlags = /*                      */ 0b000000000000000000
const PerformedWork = /*                */ 0b000000000000000001
const Placement = /*                    */ 0b000000000000000010
const Update = /*                       */ 0b000000000000000100
const PlacementAndUpdate = /*           */ 0b000000000000000110
const Deletion = /*                     */ 0b000000000000001000
const ContentReset = /*                 */ 0b000000000000010000
const Callback = /*                     */ 0b000000000000100000
const DidCapture = /*                   */ 0b000000000001000000
const Ref = /*                          */ 0b000000000010000000
const Snapshot = /*                     */ 0b000000000100000000
const Passive = /*                      */ 0b000000001000000000
const PassiveUnmountPendingDev = /*     */ 0b000010000000000000
const Hydrating = /*                    */ 0b000000010000000000
const HydratingAndUpdate = /*           */ 0b000000010000000100
const LifecycleEffectMask = /*          */ 0b000000001110100100
const HostEffectMask = /*               */ 0b000000011111111111
const Incomplete = /*                   */ 0b000000100000000000
const ShouldCapture = /*                */ 0b000001000000000000
const ForceUpdateForLegacySuspense = /* */ 0b000100000000000000
const PassiveStatic = /*                */ 0b001000000000000000
const BeforeMutationMask = /*           */ 0b000000001100001010
const MutationMask = /*                 */ 0b000000010010011110
const LayoutMask = /*                   */ 0b000000000010100100
const PassiveMask = /*                  */ 0b000000001000001000
const StaticMask = /*                   */ 0b001000000000000000
const MountLayoutDev = /*               */ 0b010000000000000000
const MountPassiveDev = /*              */ 0b100000000000000000
React Fiber Lanes
- Legacy 模式: 返回 SyncLane.
 - Blocking 模式: 返回 SyncLane.
 - Concurrent 模式:
- 正常情况: 根据当前的调度优先级来生成一个 lane.
 - 处于 Suspense 过程中: 会优先选择 
TransitionLanes通道中的空闲通道 (或最高优先级). 
 
export function requestUpdateLane(fiber: Fiber): Lane {
  const mode = fiber.mode
  if ((mode & BlockingMode) === NoMode) {
    // Legacy 模式.
    return SyncLane
  } else if ((mode & ConcurrentMode) === NoMode) {
    // Blocking 模式.
    return getCurrentPriorityLevel() === ImmediateSchedulerPriority
      ? SyncLane
      : SyncBatchedLane
  }
  // Concurrent 模式.
  if (currentEventWipLanes === NoLanes)
    currentEventWipLanes = workInProgressRootIncludedLanes
  const isTransition = requestCurrentTransition() !== NoTransition
  if (isTransition) {
    // 特殊情况, 处于 Suspense 过程中.
    if (currentEventPendingLanes !== NoLanes) {
      currentEventPendingLanes
        = mostRecentlyUpdatedRoot !== null
          ? mostRecentlyUpdatedRoot.pendingLanes
          : NoLanes
    }
    return findTransitionLane(currentEventWipLanes, currentEventPendingLanes)
  }
  // 正常情况, 获取调度优先级.
  let lane
  const schedulerPriority = getCurrentPriorityLevel()
  if (
    (executionContext & DiscreteEventContext) !== NoContext
    && schedulerPriority === UserBlockingSchedulerPriority
  ) {
    // `executionContext` 存在输入事件, 且调度优先级是用户阻塞性质.
    lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes)
  } else {
    // 调度优先级转换为车道模型.
    const schedulerLanePriority
      = schedulerPriorityToLanePriority(schedulerPriority)
    lane = findUpdateLane(schedulerLanePriority, currentEventWipLanes)
  }
  return lane
}
Fiber 树构造过程中 (Render Phase),
若 Fiber 对象或 Update 对象优先级 (fiber.lanes/update.lane) 比  全局渲染优先级低,
则将会被忽略 (节点未更新, 可以直接复用).
export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes {
  const pendingLanes = root.pendingLanes
  if (pendingLanes === NoLanes)
    return NoLanes
  let nextLanes = NoLanes
  const suspendedLanes = root.suspendedLanes
  const pingedLanes = root.pingedLanes
  const nonIdlePendingLanes = pendingLanes & NonIdleLanes
  if (nonIdlePendingLanes !== NoLanes) {
    const nonIdleUnblockedLanes = nonIdlePendingLanes & ~suspendedLanes
    if (nonIdleUnblockedLanes !== NoLanes) {
      nextLanes = getHighestPriorityLanes(nonIdleUnblockedLanes)
    } else {
      const nonIdlePingedLanes = nonIdlePendingLanes & pingedLanes
      if (nonIdlePingedLanes !== NoLanes)
        nextLanes = getHighestPriorityLanes(nonIdlePingedLanes)
    }
  } else {
    const unblockedLanes = pendingLanes & ~suspendedLanes
    if (unblockedLanes !== NoLanes) {
      nextLanes = getHighestPriorityLanes(unblockedLanes)
    } else {
      if (pingedLanes !== NoLanes)
        nextLanes = getHighestPriorityLanes(pingedLanes)
    }
  }
  if (nextLanes === NoLanes)
    return NoLanes
  if (
    wipLanes !== NoLanes
    && wipLanes !== nextLanes
    && (wipLanes & suspendedLanes) === NoLanes
  ) {
    const nextLane = getHighestPriorityLane(nextLanes)
    const wipLane = getHighestPriorityLane(wipLanes)
    if (
      nextLane >= wipLane
      || (nextLane === DefaultLane && (wipLane & TransitionLanes) !== NoLanes)
    )
      return wipLanes
  }
  if (
    allowConcurrentByDefault
    && (root.current.mode & ConcurrentUpdatesByDefaultMode) !== NoMode
  ) {
    // Do nothing, use the lanes as they were assigned.
  } else if ((nextLanes & InputContinuousLane) !== NoLanes) {
    nextLanes |= pendingLanes & DefaultLane
  }
  const entangledLanes = root.entangledLanes
  if (entangledLanes !== NoLanes) {
    const entanglements = root.entanglements
    let lanes = nextLanes & entangledLanes
    while (lanes > 0) {
      const index = pickArbitraryLaneIndex(lanes)
      const lane = 1 << index
      nextLanes |= entanglements[index]
      lanes &= ~lane
    }
  }
  return nextLanes
}
Lanes model use case:
// task 与 batchTask 的优先级是否重叠:
// 1. expirationTime:
const isTaskIncludedInBatch = priorityOfTask >= priorityOfBatch
// 2. Lanes:
const isTaskIncludedInBatch = (task & batchOfTasks) !== 0
// 当同时处理一组任务, 该组内有多个任务, 且每个任务的优先级不一致:
// 1. expirationTime:
const isTaskIncludedInBatch
  = taskPriority <= highestPriorityInRange
  && taskPriority >= lowestPriorityInRange
// 2. Lanes:
const isTaskIncludedInBatch = (task & batchOfTasks) !== 0
// 从 group 中增删 task:
// 1. expirationTime (need list):
task.prev.next = task.next
let current = queue
while (task.expirationTime >= current.expirationTime)
  current = current.next
task.next = current.next
current.next = task
const isTaskIncludedInBatch
  = taskPriority <= highestPriorityInRange
  && taskPriority >= lowestPriorityInRange
// 2. Lanes:
batchOfTasks &= ~task // Delete task.
batchOfTasks |= task // Add task.
const isTaskIncludedInBatch = (task & batchOfTasks) !== 0
React Fiber Trees
currentFiber tree: rendered to screen.workInProgressFiber tree: under reconciliation.- When 
workInProgressFiber tree completerender+commit, swap 2 Fiber tree:- Reuse Fiber objects.
 - Reduce memory usage and GC time.
 
 FiberRoot:FiberRoot.current = currentHostRootFiber.FiberRoot.finishedWork = workInProgressHostRootFiber.currentHostRootFiber.stateNode = FiberRoot.workInProgressHostRootFiber.stateNode = FiberRoot.currentHostRootFiber.alternate = workInProgressHostRootFiberworkInProgressHostRootFiber.alternate = currentHostRootFiber
ReactElementtree ->Fibertree ->DOMtree.
React Fiber Work Loop
React Reconciler
Reconciler Render Workflow
Reconciler construct Fiber tree:
- scheduleUpdateOnFiber:
- 首次 render 直接调用 
performWorkOnRoot. - 再次 render 需要调用 
ensureRootIsScheduled. 
 - 首次 render 直接调用 
 - ensureRootIsScheduled.
 - flushSyncCallbacks.
 - performSyncWorkOnRoot / performConcurrentWorkOnRoot:
performConcurrentWorkOnRoot支持可中断渲染:- 此函数首先检查是否处于 render 过程中, 是否需要恢复上一次渲染.
 - 如果本次渲染被中断,
此函数最后返回一个新的 
performConcurrentWorkOnRoot函数, 等待下一次 Scheduler 调度. 
 - renderRootSync / renderRootConcurrent:
- 此函数会调用 
prepareFreshStack, 重置 FiberRoot 上的全局属性, 重置 Fiber Work Loop 全局变量. - 此函数会设置 
workInProgressRoot = FiberRoot, 表示正在进行 render. - 此函数退出前, 会重置 
workInProgressRoot = null, 表示没有正在进行中的 render. - 此函数退出前, 会挂载 
FiberRoot.finishedWork = workInProgressHostRootFiber. 此时HostRootFiber上挂载了副作用队列, 层级越深子节点副作用越靠前. 
 - 此函数会调用 
 - workLoopSync / workLoopConcurrent:
循环调用 
performUnitOfWork, 直到workInProgress === null或用完当前时间分片. - performUnitOfWork(workInProgress):
- 存在子节点, 
beginWork与completeUnitOfWork不在同一次循环里调用: 执行完beginWork后, 优先向下遍历, 执行子节点的beginWork与completeUnitOfWork, 在 N 次循环后再向上回溯. - 不存在子节点, 
beginWork与completeUnitOfWork在同一次循环里调用. - 若 
beginWork返回next节点, 则设置workInProgress = next进行 DFS 遍历, 再次调用此函数. - 若 
beginWork返回null节点, 则调用completeUnitOfWork函数完成节点处理. - 若存在兄弟节点,
completeUnitOfWork会设置workInProgress = siblingFiber进行 DFS 遍历, 再次调用此函数. - 若到达子叶节点,
completeUnitOfWork会设置workInProgress = returnFiber进行 DFS 回溯, 再次调用此函数. 
 - 存在子节点, 
 - beginWork:
- 根据 
ReactElement对象创建所有的 Fiber 节点, 最终构造出 Fiber 树形结构 (设置return和sibling指针). - 调用 
updateXXX, 设置fiber.flags/fiber.stateNode等状态. - 非子叶节点返回子节点, 进行 DFS 遍历; 子叶节点返回 
null, 直接进入completeUnitOfWork阶段. 
 - 根据 
 - updateHostRoot/updateXXXComponent:
- 根据 
fiber.pendingProps/fiber.updateQueue等输入数据状态, 计算fiber.memoizedState作为输出状态. - ClassComponent:
- 构建 
React.Component实例. - 把新实例挂载到 
fiber.stateNode上. - 执行 
render之前的生命周期函数. - 执行 
render方法, 获取下级ReactElement. - 设置 
fiber.flags, 标记副作用. 
 - 构建 
 - FunctionComponent:
- 执行 
renderWithHooks()->FunctionComponent(), 获取下级ReactElement. - 设置 
fiber.flags, 标记副作用. 
 - 执行 
 - HostComponent.
pendingProps.children作为下级ReactElement.- 如果下级节点是文本节点, 则设置下级节点为 
null(进入completeUnitOfWork阶段). - 设置 
fiber.flags, 标记副作用. 
 - 根据实际情况, 设置 
fiber.flags, 标记副作用. - 根据获取的下级 
ReactElement对象, 调用reconcileChildren生成Fiber子节点 (只生成次级子节点). 
 - 根据 
 ReactDOMComponent.createElement()/ReactClassComponent.render()/ReactFunctionComponent().- reconcileChildren.
 - mountChildFibers/reconcileChildFibers:
mountChildFibers: similar logic, not tracking side effects.reconcileChildFibers: similar logic, tracking side effects.reconcileSingleElement.reconcileSingleTextNode.reconcileSinglePortal.reconcileChildrenArray.reconcileChildrenIterator.
 - completeUnitOfWork:
- 当 
reconcileChildren返回值为null时, 表示 DFS 进行到子叶节点,performUnitOfWork会调用completeUnitOfWork函数. - 调用 
completeWork进行render. - 把当前 Fiber 对象的副作用队列 (
firstEffect与lastEffect) 加到父节点的副作用队列之后, 更新父节点的firstEffect和lastEffect指针. - 识别 
beginWork阶段设置的fiber.flags, 若当前 Fiber 存在副作用 (Effects), 则将当前 Fiber 加入到父节点的 Effects 队列, 等待 Commit 阶段处理. - 将 
workInProgress设置为siblingFiber(DFS 遍历) 或returnFiber(DFS 回溯), 继续构建 Fiber 树. 
 - 当 
 - completeWork:
- 创建 DOM 实例, 绑定至 
HostComponent/HostTextfiber.stateNode(局部状态). - 设置 DOM 节点属性, 绑定事件.
 - 设置 
fiber.flags, 收集副作用. 
 - 创建 DOM 实例, 绑定至 
 
export function scheduleUpdateOnFiber(
  fiber: Fiber,
  lane: Lane,
  eventTime: number
) {
  const root = markUpdateLaneFromFiberToRoot(fiber, lane)
  if (lane === SyncLane) {
    if (
      (executionContext & LegacyUnbatchedContext) !== NoContext
      && (executionContext & (RenderContext | CommitContext)) === NoContext
    ) {
      // 初次渲染.
      performSyncWorkOnRoot(root)
    } else {
      // 对比更新.
      ensureRootIsScheduled(root, eventTime)
    }
  }
  mostRecentlyUpdatedRoot = root
}
function performSyncWorkOnRoot(root) {
  // 1. 获取本次render的优先级, 初次构造返回 NoLanes.
  const lanes = getNextLanes(root, NoLanes)
  // 2. 从root节点开始, 至上而下更新.
  const exitStatus = renderRootSync(root, lanes)
  // 3. 将最新的 Fiber 树挂载到 root.finishedWork 节点上.
  const finishedWork: Fiber = root.current.alternate
  root.finishedWork = finishedWork
  root.finishedLanes = lanes
  // 4. 进入 Commit 阶段.
  commitRoot(root)
}
function performConcurrentWorkOnRoot(root) {
  const originalCallbackNode = root.callbackNode
  // 1. 刷新 pending 状态的 effects, 有可能某些 effect 会取消本次任务.
  const didFlushPassiveEffects = flushPassiveEffects()
  if (didFlushPassiveEffects) {
    if (root.callbackNode !== originalCallbackNode) {
      // 任务被取消, 退出调用.
      return null
    } else {
      // Current task was not canceled. Continue.
    }
  }
  // 2. 获取本次渲染的优先级.
  const lanes = getNextLanes(
    root,
    root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes
  )
  // 3. 构造 Fiber 树.
  const exitStatus = renderRootConcurrent(root, lanes)
  if (
    includesSomeLane(
      workInProgressRootIncludedLanes,
      workInProgressRootUpdatedLanes
    )
  ) {
    // 如果在 render 过程中产生了新 update, 且新 update 的优先级与最初 render 的优先级有交集.
    // 那么最初 render 无效, 丢弃最初 render 的结果, 等待下一次调度.
    prepareFreshStack(root, NoLanes)
  } else if (exitStatus !== RootIncomplete) {
    // 4. 异常处理: 有可能fiber构造过程中出现异常.
    if (exitStatus === RootError)
      processError()
    const finishedWork = root.current.alternate // Fiber
    root.finishedWork = finishedWork
    root.finishedLanes = lanes
    // 5. 输出: 渲染 Fiber树.
    finishConcurrentRender(root, exitStatus, lanes)
  }
  // 退出前再次检测, 是否还有其他更新, 是否需要发起新调度.
  ensureRootIsScheduled(root, now())
  if (root.callbackNode === originalCallbackNode) {
    // 渲染被阻断, 返回一个新的 performConcurrentWorkOnRoot 函数, 等待下一次调度.
    return performConcurrentWorkOnRoot.bind(null, root)
  }
  return null
}
function renderRootSync(root: FiberRoot, lanes: Lanes) {
  const prevExecutionContext = executionContext
  executionContext |= RenderContext
  // 如果 FiberRoot 变动, 或者 update.lane 变动, 都会刷新栈帧, 丢弃上一次渲染进度.
  if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
    // 刷新栈帧.
    prepareFreshStack(root, lanes)
  }
  do {
    try {
      workLoopSync()
      break
    } catch (thrownValue) {
      handleError(root, thrownValue)
    }
  } while (true)
  // 重置全局变量, 表明 render 结束.
  executionContext = prevExecutionContext
  workInProgressRoot = null
  workInProgressRootRenderLanes = NoLanes
  return workInProgressRootExitStatus
}
function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
  const prevExecutionContext = executionContext
  executionContext |= RenderContext
  const prevDispatcher = pushDispatcher()
  // 如果 FiberRoot 变动, 或者 update.lane变动, 都会刷新栈帧, 丢弃上一次渲染进度.
  if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
    resetRenderTimer()
    // 刷新栈帧.
    prepareFreshStack(root, lanes)
    startWorkOnPendingInteractions(root, lanes)
  }
  const prevInteractions = pushInteractions(root)
  do {
    try {
      workLoopConcurrent()
      break
    } catch (thrownValue) {
      handleError(root, thrownValue)
    }
  } while (true)
  // 重置全局变量.
  resetContextDependencies()
  popDispatcher(prevDispatcher)
  executionContext = prevExecutionContext
  // Check if the tree has completed.
  if (workInProgress !== null) {
    // Still work remaining.
    return RootIncomplete
  } else {
    // Completed the tree.
    // Set this to null to indicate there's no in-progress render.
    workInProgressRoot = null
    workInProgressRootRenderLanes = NoLanes
    // Return the final exit status.
    return workInProgressRootExitStatus
  }
}
function prepareFreshStack(root: FiberRoot, lanes: Lanes) {
  // 重置 FiberRoot 上的属性.
  root.finishedWork = null
  root.finishedLanes = NoLanes
  const timeoutHandle = root.timeoutHandle
  if (timeoutHandle !== noTimeout) {
    root.timeoutHandle = noTimeout
    cancelTimeout(timeoutHandle)
  }
  if (workInProgress !== null) {
    let interruptedWork = workInProgress.return
    while (interruptedWork !== null) {
      unwindInterruptedWork(interruptedWork)
      interruptedWork = interruptedWork.return
    }
  }
  // 重置全局变量.
  workInProgressRoot = root
  workInProgress = createWorkInProgress(root.current, null) // currentHostRootFiber.alternate.
  workInProgressRootRenderLanes
    = subtreeRenderLanes
    = workInProgressRootIncludedLanes
      = lanes
  workInProgressRootExitStatus = RootIncomplete
  workInProgressRootFatalError = null
  workInProgressRootSkippedLanes = NoLanes
  workInProgressRootUpdatedLanes = NoLanes
  workInProgressRootPingedLanes = NoLanes
}
function workLoopSync() {
  while (workInProgress !== null)
    performUnitOfWork(workInProgress)
}
function workLoopConcurrent() {
  // Perform work until Scheduler asks us to yield.
  while (workInProgress !== null && !shouldYield())
    performUnitOfWork(workInProgress)
}
function performUnitOfWork(unitOfWork: Fiber): void {
  // unitOfWork 就是被传入的 workInProgress.
  const current = unitOfWork.alternate
  const next = beginWork(current, unitOfWork, subtreeRenderLanes)
  unitOfWork.memoizedProps = unitOfWork.pendingProps
  if (next === null) {
    // 如果没有派生出新的下级节点, 则进入 completeWork 阶段, 传入的是当前 unitOfWork.
    completeUnitOfWork(unitOfWork)
  } else {
    // 如果派生出新的下级节点, 则递归处理.
    workInProgress = next
  }
}
function _performUnitOfWork_Recursive(unitOfWork: Fiber): void {
  beginWork(unitOfWork.alternate, unitOfWork, subtreeRenderLanes)
  if (unitOfWork.child)
    _performUnitOfWork_Recursive(unitOfWork.child)
  completeUnitOfWork(unitOfWork)
  if (unitOfWork.sibling)
    _performUnitOfWork_Recursive(unitOfWork.sibling)
}
function beginWork(
  current: Fiber | null,
  workInProgress: Fiber,
  renderLanes: Lanes
): Fiber | null {
  // 1. 设置 workInProgress 优先级为 NoLanes (最高优先级).
  const updateLanes = workInProgress.lanes
  didReceiveUpdate = false
  workInProgress.lanes = NoLanes
  // 2. 根据 workInProgress 节点的类型, 用不同的方法派生出子节点.
  switch (workInProgress.tag) {
    case ClassComponent: {
      const Component = workInProgress.type
      const unresolvedProps = workInProgress.pendingProps
      const resolvedProps
        = workInProgress.elementType === Component
          ? unresolvedProps
          : resolveDefaultProps(Component, unresolvedProps)
      return updateClassComponent(
        current,
        workInProgress,
        Component,
        resolvedProps,
        renderLanes
      )
    }
    case HostRoot:
      return updateHostRoot(current, workInProgress, renderLanes)
    case HostComponent:
      return updateHostComponent(current, workInProgress, renderLanes)
    case HostText:
      return updateHostText(current, workInProgress)
    case Fragment:
      return updateFragment(current, workInProgress, renderLanes)
  }
}
function completeUnitOfWork(unitOfWork: Fiber): void {
  let completedWork = unitOfWork
  // 外层循环控制并移动指针 (workInProgress/completedWork).
  do {
    const current = completedWork.alternate
    const returnFiber = completedWork.return
    if ((completedWork.flags & Incomplete) === NoFlags) {
      // 1. 处理 Fiber 节点, 会调用渲染器 (关联 Fiber 节点和 DOM 对象, 绑定事件等).
      const next = completeWork(current, completedWork, subtreeRenderLanes)
      if (next !== null) {
        // 如果派生出其他的子节点, 则回到 beginWork 阶段进行处理.
        workInProgress = next
        return
      }
      // 重置子节点的优先级.
      resetChildLanes(completedWork)
      if (
        returnFiber !== null
        && (returnFiber.flags & Incomplete) === NoFlags
      ) {
        // 2. 收集当前 Fiber 节点以及其子树的副作用 Effects.
        // 2.1 把子节点的副作用队列添加到父节点上.
        if (returnFiber.firstEffect === null)
          returnFiber.firstEffect = completedWork.firstEffect
        if (completedWork.lastEffect !== null) {
          if (returnFiber.lastEffect !== null)
            returnFiber.lastEffect.nextEffect = completedWork.firstEffect
          returnFiber.lastEffect = completedWork.lastEffect
        }
        // 2.2 如果当前 Fiber 节点有副作用, 将其添加到子节点的副作用队列之后.
        const flags = completedWork.flags
        if (returnFiber.lastEffect !== null)
          returnFiber.lastEffect.nextEffect = completedWork
        else
          returnFiber.firstEffect = completedWork
        returnFiber.lastEffect = completedWork
      }
    }
    const siblingFiber = completedWork.sibling
    if (siblingFiber !== null) {
      // 如果有兄弟节点, 返回之后再次进入 beginWork 阶段.
      workInProgress = siblingFiber
      return
    }
    // 移动指针, 指向下一个节点.
    completedWork = returnFiber
    workInProgress = completedWork
  } while (completedWork !== null)
  // 已回溯到根节点, 设置 workInProgressRootExitStatus = RootCompleted.
  if (workInProgressRootExitStatus === RootIncomplete)
    workInProgressRootExitStatus = RootCompleted
}
function completeWork(
  current: Fiber | null,
  workInProgress: Fiber,
  renderLanes: Lanes
): Fiber | null {
  const newProps = workInProgress.pendingProps
  switch (workInProgress.tag) {
    case HostRoot: {
      const fiberRoot: FiberRoot = workInProgress.stateNode
      if (fiberRoot.pendingContext) {
        fiberRoot.context = fiberRoot.pendingContext
        fiberRoot.pendingContext = null
      }
      if (current === null || current.child === null) {
        // 设置 fiber.flags.
        workInProgress.flags |= Snapshot
      }
      return null
    }
    case HostComponent: {
      popHostContext(workInProgress)
      const rootContainerInstance = getRootHostContainer()
      const type = workInProgress.type
      const currentHostContext = getHostContext()
      // 1. 创建 DOM 对象.
      const instance = createInstance(
        type,
        newProps,
        rootContainerInstance,
        currentHostContext,
        workInProgress
      )
      // 2. 把子树中的 DOM 对象 append 到本节点的 DOM 对象之后.
      appendAllChildren(instance, workInProgress, false, false)
      // 3. 设置 stateNode 属性, 指向 DOM 对象.
      workInProgress.stateNode = instance
      if (
        // 4. 设置DOM对象的属性, 绑定事件等.
        finalizeInitialChildren(
          instance,
          type,
          newProps,
          rootContainerInstance,
          currentHostContext
        )
      ) {
        // 设置 fiber.flags (Update).
        markUpdate(workInProgress)
      }
      if (workInProgress.ref !== null) {
        // 设置 fiber.flags (Ref).
        markRef(workInProgress)
      }
      return null
    }
  }
}
Host Root Fiber Rendering
function updateHostRoot(current, workInProgress, renderLanes) {
  // 1. 状态计算, 更新整合到 workInProgress.memoizedState.
  const updateQueue = workInProgress.updateQueue
  const nextProps = workInProgress.pendingProps
  const prevState = workInProgress.memoizedState
  const prevChildren = prevState !== null ? prevState.element : null
  cloneUpdateQueue(current, workInProgress)
  // 遍历 updateQueue.shared.pending, 提取有足够优先级的 update对象, 计算出最终的状态 workInProgress.memoizedState.
  processUpdateQueue(workInProgress, nextProps, null, renderLanes)
  const nextState = workInProgress.memoizedState
  // 2. 获取下级 ReactElement 对象.
  const nextChildren = nextState.element
  const root: FiberRoot = workInProgress.stateNode
  // 3. 根据 ReactElement 对象, 调用 reconcileChildren 生成 Fiber 子节点 (只生成次级子节点).
  reconcileChildren(current, workInProgress, nextChildren, renderLanes)
  return workInProgress.child
}
Host Component Fiber Rendering
function updateHostComponent(
  current: Fiber | null,
  workInProgress: Fiber,
  renderLanes: Lanes
) {
  // 1. 状态计算, 由于 HostComponent 是无状态组件, 只需要收集 nextProps.
  const type = workInProgress.type
  const nextProps = workInProgress.pendingProps
  const prevProps = current !== null ? current.memoizedProps : null
  // 2. 获取下级 ReactElement 对象.
  let nextChildren = nextProps.children
  const isDirectTextChild = shouldSetTextContent(type, nextProps)
  if (isDirectTextChild) {
    // 如果子节点只有一个文本节点, 不用再创建一个 HostText 类型的 Fiber.
    nextChildren = null
  } else if (prevProps !== null && shouldSetTextContent(type, prevProps)) {
    // 设置 fiber.flags.
    workInProgress.flags |= ContentReset
  }
  // 设置 fiber.flags.
  markRef(current, workInProgress)
  // 3. 根据 ReactElement 对象, 调用 reconcileChildren 生成 Fiber 子节点(只生成次级子节点)
  reconcileChildren(current, workInProgress, nextChildren, renderLanes)
  return workInProgress.child
}
Class Component Fiber Rendering
Function Component Fiber Rendering
Reconciler Update Workflow
UpdateQueue是一个循环队列.- 创建 
Update时机 (createUpdate/enqueueUpdate):ReactFiberReconciler.updateContainer.ReactFiberClassComponent.setState.ReactFiberHooks.dispatchAction.
 Reconciler.Render阶段, 调用XXXClassInstance/useXXX, 遍历处理 Update Queue (processUpdateQueue/HooksDispatcherOnUpdate), 计算出 memoizedState, 利用 pendingProps 与 memoizedState 产生新的 ReactElement (ClassComponent.render()/FunctionComponent()).
interface Update<State> {
  lane: Lane
  tag: 'UpdateState' | 'ReplaceState' | 'ForceUpdate' | 'CaptureUpdate'
  payload: any
  callback: (() => mixed) | null
  next: Update<State> | null
  _eventTime: number
}
interface SharedQueue<State> {
  pending: Update<State> | null
}
interface UpdateQueue<State> {
  baseState: State
  firstBaseUpdate: Update<State> | null
  lastBaseUpdate: Update<State> | null
  shared: SharedQueue<State>
  effects: Array<Update<State>> | null // Updates with `callback`.
}
ReactFiberClassComponent.setState:
const classComponentUpdater = {
  isMounted,
  enqueueSetState(inst, payload, callback) {
    // 1. 获取 ClassComponent 实例对应的 Fiber 节点.
    const fiber = getInstance(inst)
    // 2. 创建 Update 对象.
    const eventTime = requestEventTime()
    const lane = requestUpdateLane(fiber)
    const update = createUpdate(eventTime, lane)
    update.payload = payload
    if (callback !== undefined && callback !== null)
      update.callback = callback
    // 3. 将 Update 对象添加到当前 Fiber 节点的 updateQueue.
    enqueueUpdate(fiber, update)
    // 4. 请求调度, 进入 Reconciler.
    scheduleUpdateOnFiber(fiber, lane, eventTime)
  },
}
ReactFiberHooks.dispatchAction:
function dispatchAction<S, A>(
  fiber: Fiber,
  queue: UpdateQueue<S, A>,
  action: A
) {
  // 1. 创建 Update 对象.
  const eventTime = requestEventTime()
  const lane = requestUpdateLane(fiber)
  const update: Update<S, A> = {
    lane,
    action,
    eagerReducer: null,
    eagerState: null,
    next: null,
  }
  // 2. 将 Update 对象添加到当前 Hook 对象的 updateQueue.
  const pending = queue.pending
  if (pending === null) {
    update.next = update
  } else {
    update.next = pending.next
    pending.next = update
  }
  queue.pending = update
  // 3. 请求调度, 进入 Reconciler.
  scheduleUpdateOnFiber(fiber, lane, eventTime)
}
- createUpdate.
 - enqueueUpdate.
 - scheduleUpdateOnFiber.
 - markUpdateLaneFromFiberToRoot:
找出 Fiber 树中受到本次 
Update影响的所有节点 (存在更新可能), 设置这些节点的fiber.lanes或fiber.childLanes. - ensureRootIsScheduled.
 - flushSyncCallbacks.
 - performSyncWorkOnRoot / performConcurrentWorkOnRoot.
 - renderRootSync / renderRootConcurrent.
 - workLoopSync / workLoopConcurrent.
 - performUnitOfWork(workInProgress).
 - beginWork:
- 若判断当前 Fiber 节点无需更新, 调用 
bailoutOnAlreadyFinishedWork循环检测子节点是否需要更新:instance.shouldComponentUpdate() === false.workInProgress.pendingProps === current.memoizedProps.hasLegacyContextChange() === false.checkIfContextChanged(fiber.dependencies) === false.includesSomeLane(fiber.lanes, renderLanes) === false.
 - 若判断当前 Fiber 节点需要更新, 调用 
UpdateXXXComponent进行更新. 
 - 若判断当前 Fiber 节点无需更新, 调用 
 - bailoutOnAlreadyFinishedWork:
- 若 
includesSomeLane(renderLanes, workInProgress.childLanes) === false表明子节点无需更新, 可直接进入回溯阶段 (completeUnitOfWork). - 若 
includesSomeLane(renderLanes, workInProgress.childLanes) === true, 表明子节点需 要更新, clone 并返回子节点. 
 - 若 
 - updateHostRoot/updateXXXComponent.
 ReactClassComponent.render()/ReactFunctionComponent()/ReactDOMComponent.createElement(): 遍历处理 Update Queue (processUpdateQueue/HooksDispatcherOnUpdate), 计算出 memoizedState, 利用 pendingProps 与 memoizedState 产生新的 ReactElement.- reconcileChildren:
- 通过 ReactElement 与 OldFiber, 产生或复用 ChildFiber.
 - 设置 
fiber.flags, 标记副作用:Placement/Deletion/etc. - 对于 
DeletionFiber, 在beginWork阶段提前将其添加到父节点的 Effects 队列中 (该节点会脱离 Fiber 树, 不会再进入completeWork阶段, 无法在此阶段收集此节点副作用). 
 - reconcileChildFibers.
 - completeUnitOfWork: 收集副作用.
 - completeWork: 收集副作用.
 
// 标记所有可能存在更新的节点, 并设置 fiber.lanes 与 fiber.childLanes.
function markUpdateLaneFromFiberToRoot(
  sourceFiber: Fiber, // 被更新的节点.
  lane: Lane
): FiberRoot | null {
  // 设置 sourceFiber.lanes.
  sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane)
  let alternate = sourceFiber.alternate
  if (alternate !== null) {
    // 同时设置 sourceFiber.alternate.lanes.
    alternate.lanes = mergeLanes(alternate.lanes, lane)
  }
  // 从 sourceFiber 开始, 向上遍历所有 Fiber, 直到 HostRootFiber.
  // 设置沿途所有 fiber.childLanes 与 fiber.alternate.childLanes.
  let node = sourceFiber
  let parent = sourceFiber.return
  while (parent !== null) {
    parent.childLanes = mergeLanes(parent.childLanes, lane)
    alternate = parent.alternate
    if (alternate !== null)
      alternate.childLanes = mergeLanes(alternate.childLanes, lane)
    node = parent
    parent = parent.return
  }
  if (node.tag === HostRoot) {
    const root: FiberRoot = node.stateNode
    return root
  } else {
    return null
  }
}
function beginWork(
  current: Fiber | null,
  workInProgress: Fiber,
  renderLanes: Lanes
): Fiber | null {
  const updateLanes = workInProgress.lanes
  if (current !== null) {
    // 进入对比.
    const oldProps = current.memoizedProps
    const newProps = workInProgress.pendingProps
    if (
      oldProps !== newProps
      || hasLegacyContextChanged()
      || (__DEV__ ? workInProgress.type !== current.type : false)
    ) {
      didReceiveUpdate = true
    } else if (!includesSomeLane(renderLanes, updateLanes)) {
      // 当前渲染优先级 renderLanes 不包括 fiber.lanes, 表明当前 Fiber 节点无需更新.
      didReceiveUpdate = false
      // 调用 bailoutOnAlreadyFinishedWork 循环检测子节点是否需要更新.
      return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes)
    }
  }
  // 当前节点需要更新.
  workInProgress.lanes = NoLanes // 最高优先级
  switch (workInProgress.tag) {
    case ClassComponent: {
      const Component = workInProgress.type
      const unresolvedProps = workInProgress.pendingProps
      const resolvedProps
        = workInProgress.elementType === Component
          ? unresolvedProps
          : resolveDefaultProps(Component, unresolvedProps)
      return updateClassComponent(
        current,
        workInProgress,
        Component,
        resolvedProps,
        renderLanes
      )
    }
    case HostRoot:
      return updateHostRoot(current, workInProgress, renderLanes)
    case HostComponent:
      return updateHostComponent(current, workInProgress, renderLanes)
    case HostText:
      return updateHostText(current, workInProgress)
    case Fragment:
      return updateFragment(current, workInProgress, renderLanes)
  }
}
function bailoutOnAlreadyFinishedWork(
  current: Fiber | null,
  workInProgress: Fiber,
  renderLanes: Lanes
): Fiber | null {
  if (!includesSomeLane(renderLanes, workInProgress.childLanes)) {
    // 渲染优先级不包括 workInProgress.childLanes, 表明子节点也无需更新.
    // 返回 null, 直接进入回溯阶段.
    return null
  } else {
    // Fiber 自身无需更新, 但子节点需要更新, clone 并返回子节点.
    cloneChildFibers(current, workInProgress)
    return workInProgress.child
  }
}
function completeWork(
  current: Fiber | null,
  workInProgress: Fiber,
  renderLanes: Lanes
): Fiber | null {
  const newProps = workInProgress.pendingProps
  switch (workInProgress.tag) {
    case HostComponent: {
      // 非文本节点.
      popHostContext(workInProgress)
      const rootContainerInstance = getRootHostContainer()
      const type = workInProgress.type
      if (current !== null && workInProgress.stateNode !== null) {
        // 处理改动.
        updateHostComponent(
          current,
          workInProgress,
          type,
          newProps,
          rootContainerInstance
        )
        if (current.ref !== workInProgress.ref)
          markRef(workInProgress)
      }
      return null
    }
    case HostText: {
      // 文本节点.
      const newText = newProps
      if (current !== null && workInProgress.stateNode !== null) {
        const oldText = current.memoizedProps
        // 处理改动.
        updateHostText(current, workInProgress, oldText, newText)
      }
      return null
    }
  }
}
function updateHostComponent(
  current: Fiber,
  workInProgress: Fiber,
  type: Type,
  newProps: Props,
  rootContainerInstance: Container
) {
  const oldProps = current.memoizedProps
  if (oldProps === newProps)
    return
  const instance: Instance = workInProgress.stateNode
  const currentHostContext = getHostContext()
  const updatePayload = prepareUpdate(
    instance,
    type,
    oldProps,
    newProps,
    rootContainerInstance,
    currentHostContext
  )
  workInProgress.updateQueue = updatePayload
  // 如果有属性变动, 设置 fiber.flags |= Update, 等待 Commit 阶段处理.
  if (updatePayload)
    markUpdate(workInProgress)
}
function updateHostText(
  current: Fiber,
  workInProgress: Fiber,
  oldText: string,
  newText: string
) {
  // 如果有属性变动, 设置 fiber.flags |= Update, 等待 Commit 阶段处理.
  if (oldText !== newText)
    markUpdate(workInProgress)
}
Reconciler Diff Workflow
Reconciler:
- O(n) incomplete tree comparison: only compare same level nodes.
 ReactElement+ Old Children Fiber -> New Children Fiber.- Create new children fiber (non exist/need update),
drop useless children fiber,
reuse old children fiber,
set 
fiber.flags:Placement/Deletion. prepare forCommitstage. keyprop to hint for Fiber nodes reuse.- Detailed diff algorithm.
 
Different Types Elements
- Rebuild element and children.
 
Same Type DOM Elements
- Only update the changed attributes.
 - Use 
keyattribute to match children. 
Best Practice: give key to <li>/<tr>/<tc> elements
(stable, predictable, unique and not array indexed).
Same Type Component Elements
- Update the props to match the new element.
 
Reconcile Array Elements
- 第一次循环: 比较公共序列:
- 从左到右逐一遍历, 遇到一个无法复用的节点则退出循环.
 
 - 第二次循环: 比较非公共序列
- 在第一次循环的基础上, 如果 oldFiber 队列遍历完成, 证明 newChildren 队列中剩余的对象全部都是新增.
 - 此时继续遍历剩余的 newChildren 队列即可, 没有额外的 diff 比较.
 - 在第一次循环的基础上, 如果 oldFiber 队列没有遍历完, 需要将 oldFiber 队列中剩余的对象都添加到一个 Map 集合中, 以 oldFiber.key 作为键.
 - 此时继续遍历剩余的 newChildren 队列, 需要用 newChild.key 到 Map 集合中进行查找, 将匹配上的 oldFiber 取出与 newChild 进行 diff 比较.
 
 - 清理工作:
- 在第二次循环结束后,
若 Map 集合中还有剩余的 oldFiber,
则说明 oldFiber 都是被删除的节点, 需要打上删除标记 (
Deletion). 
 - 在第二次循环结束后,
若 Map 集合中还有剩余的 oldFiber,
则说明 oldFiber 都是被删除的节点, 需要打上删除标记 (
 
Reconciler Commit Workflow
Renderer and HostConfig Protocol
Renderer:
- Implementing 
HostConfigprotocol. - Rendering fiber tree to real contents:
- Web: DOM node.
 - Native: native UI.
 - Server: SSR strings.
 
 - Real renderer demo.
 
HostConfig protocol:
isPrimaryRender: true.supportsHydration: true: SSR renderer.supportsMutation: true: React DOM renderer.supportsPersistence: true: React Native renderer.- Platform timer functions:
- now.
 - scheduleTimeout.
 - cancelTimeout.
 
 - Creation operations:
- createInstance.
 - createTextInstance.
 
 - UI tree operations:
- appendInitialChild.
 - appendChild.
 - appendChildToContainer.
 - removeChildFromContainer.
 - removeChild.
 - clearContainer.
 
 - Update props operations:
- finalizeInitialChildren.
 - prepareUpdate.
 - commitUpdate.
 - commitTextUpdate.
 - shouldSetTextContent.
 - resetTextContent.
 
 - Context and schedule operations:
- getRootHostContext.
 - getChildHostContext.
 - getPublicInstance.
 - prepareForCommit.
 - resetAfterCommit.
 - preparePortalMount.
 
 
Commit Root
FiberRoot.finishedWork:- 副作用队列挂载在根节点上 (
finishedWork.firstEffect). - 最新 DOM 对象挂载在 HostComponent Fiber 上 (
fiber.stateNode). 
- 副作用队列挂载在根节点上 (
 BeforeMutationphase:- Read the state of the host tree right before DOM mutation.
 - Process
Passive/Snapshot/Deletioneffects fiber. instance.getSnapshotBeforeUpdate.
Mutationphase.- Mutate the host tree, render UI.
 - Process
ContentReset/Ref/Visibility/Placement/Update/Deletion/Hydratingeffects fiber. 
Layoutphase.- After DOM mutation.
 - Process 
Update | Callbackeffects fiber. instance.componentDidMount/componentDidUpdate(synchronous).instancecallback forsetState.useLayoutEffect(synchronous).
CommitEffectsfunctions located in ReactFiberCommitWork.
function commitRoot(root: FiberRoot, recoverableErrors: null | Array<mixed>) {
  const previousUpdateLanePriority = getCurrentUpdatePriority()
  const prevTransition = ReactCurrentBatchConfig.transition
  try {
    ReactCurrentBatchConfig.transition = null
    setCurrentUpdatePriority(DiscreteEventPriority)
    commitRootImpl(root, recoverableErrors, previousUpdateLanePriority)
  } finally {
    ReactCurrentBatchConfig.transition = prevTransition
    setCurrentUpdatePriority(previousUpdateLanePriority)
  }
  return null
}
function commitRootImpl(
  root: FiberRoot,
  recoverableErrors: null | Array<mixed>,
  renderPriorityLevel: EventPriority
) {
  do
    flushPassiveEffects()
  while (rootWithPendingPassiveEffects !== null)
  flushRenderPhaseStrictModeWarningsInDEV()
  if ((executionContext & (RenderContext | CommitContext)) !== NoContext)
    throw new Error('Should not already be working.')
  const finishedWork = root.finishedWork
  const lanes = root.finishedLanes
  if (finishedWork === null)
    return null
  // 清空 FiberRoot 对象上的属性.
  root.finishedWork = null
  root.finishedLanes = NoLanes
  root.callbackNode = null
  root.callbackPriority = NoLane
  // Update the first and last pending times on this root.
  // The new first pending time is whatever is left on the root fiber.
  const remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes)
  if (root === workInProgressRoot) {
    // We can reset these now that they are finished.
    workInProgressRoot = null
    workInProgress = null
    workInProgressRootRenderLanes = NoLanes
  }
  // If there are pending passive effects, schedule a callback to process them.
  // Do this as early as possible before anything else in commit phase.
  if (
    (finishedWork.subtreeFlags & PassiveMask) !== NoFlags
    || (finishedWork.flags & PassiveMask) !== NoFlags
  ) {
    if (!rootDoesHavePassiveEffects) {
      rootDoesHavePassiveEffects = true
      pendingPassiveEffectsRemainingLanes = remainingLanes
      scheduleCallback(NormalSchedulerPriority, () => {
        flushPassiveEffects()
        return null
      })
    }
  }
  // Check if there are any effects in the whole tree.
  const subtreeHasEffects
    = (finishedWork.subtreeFlags
    & (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask))
    !== NoFlags
  const rootHasEffect
    = (finishedWork.flags
    & (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask))
    !== NoFlags
  if (subtreeHasEffects || rootHasEffect) {
    // Store context.
    const prevTransition = ReactCurrentBatchConfig.transition
    const previousPriority = getCurrentUpdatePriority()
    const prevExecutionContext = executionContext
    ReactCurrentBatchConfig.transition = null
    setCurrentUpdatePriority(DiscreteEventPriority)
    executionContext |= CommitContext
    // Reset this to null before calling life cycles.
    ReactCurrentOwner.current = null
    // `BeforeMutation` phase:
    // read the state of the host tree right before we mutate it.
    // `getSnapshotBeforeUpdate` is called.
    commitBeforeMutationEffects(root, finishedWork)
    // `Mutation` phase:
    // mutate the host tree.
    commitMutationEffects(root, finishedWork, lanes)
    resetAfterCommit(root.containerInfo)
    // The workInProgress tree is now the current tree (during `componentDidMount`/`Update`).
    root.current = finishedWork
    // `Layout` phase:
    // `useLayoutEffect` is called.
    commitLayoutEffects(finishedWork, root, lanes)
    // Tell Scheduler to yield at the end of the frame,
    // so the browser has an opportunity to paint.
    requestPaint()
    // Restore context.
    executionContext = prevExecutionContext
    setCurrentUpdatePriority(previousPriority)
    ReactCurrentBatchConfig.transition = prevTransition
  } else {
    // No effects.
    root.current = finishedWork
  }
  const rootDidHavePassiveEffects = rootDoesHavePassiveEffects
  if (rootDoesHavePassiveEffects) {
    // This commit has passive effects:
    // Stash a reference to them.
    rootDoesHavePassiveEffects = false
    rootWithPendingPassiveEffects = root
    pendingPassiveEffectsLanes = lanes
  } else {
    // There were no passive effects:
    // immediately release the cache pool for this render.
    releaseRootPooledCache(root, remainingLanes)
  }
  // Always call this before exiting `commitRoot`,
  // to ensure that any additional work on this root is scheduled.
  ensureRootIsScheduled(root, now())
  // If the passive effects are the result of a discrete render,
  // flush them synchronously at the end of the current task
  // so that the result is immediately observable.
  if (
    includesSomeLane(pendingPassiveEffectsLanes, SyncLane)
    && root.tag !== LegacyRoot
  )
    flushPassiveEffects()
  // If layout work was scheduled, flush it now.
  flushSyncCallbacks()
  return null
}
const BeforeMutationMask = Update | Snapshot | ChildDeletion | Visibility
const MutationMask
  = Placement
  | Update
  | ChildDeletion
  | ContentReset
  | Ref
  | Hydrating
  | Visibility
const LayoutMask = Update | Callback | Ref | Visibility
Before Mutation Phase
Passiveeffects:FunctionComponentfiber (hooks): If there are pending passive effects, schedule a callback (asynchronous) to process them, as early as possible before anything else in commit phase.useXXXhooks normally run in asynchronous mode.useEffect(asynchronous) run afteruseLayoutEffect.
Snapshoteffects:HostRootfiber:HostConfig.clearContainer.ClassComponentfiber:instance.getSnapShotBeforeUpdate.
Deletioneffects:commitBeforeMutationEffectsDeletion->HostConfig.beforeActiveInstanceBlur.
// `Passive` effects.
scheduleCallback(NormalSchedulerPriority, () => {
  flushPassiveEffects()
  return null
})
function flushPassiveEffects(): boolean {
  // Returns whether passive effects were flushed.
  if (pendingPassiveEffectsRenderPriority !== NoSchedulerPriority) {
    const priorityLevel
      = pendingPassiveEffectsRenderPriority > NormalSchedulerPriority
        ? NormalSchedulerPriority
        : pendingPassiveEffectsRenderPriority
    pendingPassiveEffectsRenderPriority = NoSchedulerPriority
    return runWithPriority(priorityLevel, flushPassiveEffectsImpl)
  }
  return false
}
function flushPassiveEffectsImpl() {
  if (rootWithPendingPassiveEffects === null)
    return false
  rootWithPendingPassiveEffects = null
  pendingPassiveEffectsLanes = NoLanes
  // 1. 执行 effect.destroy().
  const unmountEffects = pendingPassiveHookEffectsUnmount
  pendingPassiveHookEffectsUnmount = []
  for (let i = 0; i < unmountEffects.length; i += 2) {
    const effect = unmountEffects[i]
    const fiber = unmountEffects[i + 1]
    const destroy = effect.destroy
    effect.destroy = undefined
    if (typeof destroy === 'function')
      destroy()
  }
  // 2. 执行新 effect.create(), 重新赋值到 effect.destroy.
  const mountEffects = pendingPassiveHookEffectsMount
  pendingPassiveHookEffectsMount = []
  for (let i = 0; i < mountEffects.length; i += 2) {
    const effect = mountEffects[i]
    const fiber = mountEffects[i + 1]
    effect.destroy = create()
  }
}
// `Snapshot` effects.
function commitBeforeMutationEffects(root: FiberRoot, firstChild: Fiber) {
  HostConfig.prepareForCommit(root.containerInfo)
  nextEffect = firstChild
  // DFS traverse.
  while (nextEffect !== null) {
    const fiber = nextEffect
    const deletions = fiber.deletions
    if (deletions !== null) {
      for (let i = 0; i < deletions.length; i++) {
        const deletion = deletions[i]
        commitBeforeMutationEffectsDeletion(deletion)
      }
    }
    const child = fiber.child
    if (
      (fiber.subtreeFlags & BeforeMutationMask) !== NoFlags
      && child !== null
    ) {
      // 1. Visit children.
      nextEffect = child
    } else {
      while (nextEffect !== null) {
        const fiber = nextEffect
        commitBeforeMutationEffectsOnFiber(fiber)
        const sibling = fiber.sibling
        // 2. Visit sibling.
        if (sibling !== null) {
          nextEffect = sibling
          break
        }
        nextEffect = fiber.return
      }
    }
  }
}
function commitBeforeMutationEffectsOnFiber(finishedWork: Fiber) {
  const current = finishedWork.alternate
  const flags = finishedWork.flags
  if ((flags & Snapshot) !== NoFlags) {
    switch (finishedWork.tag) {
      case ClassComponent: {
        if (current !== null) {
          const prevProps = current.memoizedProps
          const prevState = current.memoizedState
          const instance = finishedWork.stateNode
          // We could update instance props and state here,
          // but instead we rely on them being set during last render.
          const snapshot = instance.getSnapshotBeforeUpdate(
            finishedWork.elementType === finishedWork.type
              ? prevProps
              : resolveDefaultProps(finishedWork.type, prevProps),
            prevState
          )
          instance.__reactInternalSnapshotBeforeUpdate = snapshot
        }
        break
      }
      case HostRoot: {
        if (supportsMutation) {
          const root = finishedWork.stateNode
          HostConfig.clearContainer(root.containerInfo)
        }
        break
      }
      case FunctionComponent:
      case ForwardRef:
      case SimpleMemoComponent:
      case HostComponent:
      case HostText:
      case HostPortal:
      case IncompleteClassComponent:
        // Nothing to do for these component types.
        break
      default: {
        throw new Error(
          'This unit of work tag should not have side-effects. This error is '
          + 'likely caused by a bug in React. Please file an issue.'
        )
      }
    }
  }
}
function commitBeforeMutationEffectsDeletion(deletion: Fiber) {
  if (doesFiberContain(deletion, focusedInstanceHandle)) {
    shouldFireAfterActiveInstanceBlur = true
    beforeActiveInstanceBlur(deletion)
  }
}
Mutation Phase
ContentReseteffects:commitResetTextContent->HostConfig.resetTextContext.Refeffects:commitAttachRef/commitDetachRef->HostConfig.getPublicInstance.Visibilityeffects:SuspenseComponentfiber:markCommitTimeOfFallback.OffscreenComponentfiber:hideOrUnhideAllChildren->HostConfig.hideInstance/hideTextInstance/unhideInstance/unhideTextInstance.
Placementeffects:commitPlacement->insertOrAppendPlacementNode/insertOrAppendPlacementNodeIntoContainer->HostConfig.appendChild/insertBefore/appendChildToContainer/insertInContainerBefore.Updateeffects:commitWork->HostConfig.commitUpdate/commitTextUpdate/commitHydratedContainer/replaceContainerChildren.Deletioneffects:commitDeletion->HostConfig.removeChild/removeChildFromContainer/clearSuspenseBoundaryFromContainer.Hydratingeffects.
export function commitMutationEffects(
  root: FiberRoot,
  firstChild: Fiber,
  committedLanes: Lanes
) {
  inProgressLanes = committedLanes
  inProgressRoot = root
  nextEffect = firstChild
  while (nextEffect !== null) {
    const fiber = nextEffect
    const deletions = fiber.deletions
    if (deletions !== null) {
      for (let i = 0; i < deletions.length; i++) {
        const childToDelete = deletions[i]
        commitDeletion(root, childToDelete, fiber)
      }
    }
    const child = fiber.child
    if ((fiber.subtreeFlags & MutationMask) !== NoFlags && child !== null) {
      // 1. Visit children.
      nextEffect = child
    } else {
      while (nextEffect !== null) {
        const fiber = nextEffect
        commitMutationEffectsOnFiber(fiber, root, lanes)
        const sibling = fiber.sibling
        // 2. Visit sibling.
        if (sibling !== null) {
          nextEffect = sibling
          break
        }
        nextEffect = fiber.return
      }
    }
  }
  inProgressLanes = null
  inProgressRoot = null
}
function commitMutationEffectsOnFiber(
  finishedWork: Fiber,
  root: FiberRoot,
  lanes: Lanes
) {
  const flags = finishedWork.flags
  if (flags & ContentReset)
    commitResetTextContent(finishedWork)
  if (flags & Ref) {
    const current = finishedWork.alternate
    if (current !== null) {
      // 先清空 ref, 在第三阶段 (Layout), 再重新赋值.
      commitDetachRef(current)
    }
    if (finishedWork.tag === ScopeComponent)
      commitAttachRef(finishedWork)
  }
  if (flags & Visibility) {
    switch (finishedWork.tag) {
      case SuspenseComponent: {
        const newState: OffscreenState | null = finishedWork.memoizedState
        const isHidden = newState !== null
        if (isHidden) {
          const current = finishedWork.alternate
          const wasHidden = current !== null && current.memoizedState !== null
          if (!wasHidden)
            markCommitTimeOfFallback()
        }
        break
      }
      case OffscreenComponent: {
        const newState: OffscreenState | null = finishedWork.memoizedState
        const isHidden = newState !== null
        const current = finishedWork.alternate
        const wasHidden = current !== null && current.memoizedState !== null
        const offscreenBoundary: Fiber = finishedWork
        if (supportsMutation)
          hideOrUnhideAllChildren(offscreenBoundary, isHidden)
        break
      }
    }
  }
  const primaryFlags = flags & (Placement | Update | Hydrating)
  switch (primaryFlags) {
    case Placement: {
      // Placement
      commitPlacement(finishedWork)
      finishedWork.flags &= ~Placement // Clear bit.
      break
    }
    case PlacementAndUpdate: {
      // Placement
      commitPlacement(finishedWork)
      finishedWork.flags &= ~Placement // Clear bit.
      // Update
      const current = finishedWork.alternate
      commitWork(current, finishedWork)
      break
    }
    case Hydrating: {
      finishedWork.flags &= ~Hydrating // Clear bit.
      break
    }
    case HydratingAndUpdate: {
      finishedWork.flags &= ~Hydrating // Clear bit.
      // Update
      const current = finishedWork.alternate
      commitWork(current, finishedWork)
      break
    }
    case Update: {
      const current = finishedWork.alternate
      commitWork(current, finishedWork)
      break
    }
  }
}
Layout Phase
Update | Callbackeffects:instance.componentDidMount/componentDidUpdate(synchronous).instancecallback forsetState.useLayoutEffect(synchronous).HostConfig.getPublicInstance/commitMount.
function commitLayoutEffects(
  finishedWork: Fiber,
  root: FiberRoot,
  committedLanes: Lanes
): void {
  inProgressLanes = committedLanes
  inProgressRoot = root
  nextEffect = finishedWork
  while (nextEffect !== null) {
    const fiber = nextEffect
    const firstChild = fiber.child
    if ((fiber.subtreeFlags & LayoutMask) !== NoFlags && firstChild !== null) {
      // 1. Visit children.
      nextEffect = firstChild
    } else {
      while (nextEffect !== null) {
        const fiber = nextEffect
        if ((fiber.flags & LayoutMask) !== NoFlags) {
          const current = fiber.alternate
          commitLayoutEffectOnFiber(root, current, fiber, committedLanes)
        }
        // Complete `commitLayoutEffects`.
        if (fiber === subtreeRoot) {
          nextEffect = null
          break
        }
        const sibling = fiber.sibling
        // 2. Visit sibling.
        if (sibling !== null) {
          nextEffect = sibling
          break
        }
        nextEffect = fiber.return
      }
    }
  }
  inProgressLanes = null
  inProgressRoot = null
}
function commitLayoutEffectOnFiber(
  finishedRoot: FiberRoot,
  current: Fiber | null,
  finishedWork: Fiber,
  committedLanes: Lanes
): void {
  if ((finishedWork.flags & LayoutMask) !== NoFlags) {
    switch (finishedWork.tag) {
      case FunctionComponent:
      case ForwardRef:
      case SimpleMemoComponent: {
        if (
          !enableSuspenseLayoutEffectSemantics
          || !offscreenSubtreeWasHidden
        )
          commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork)
        break
      }
      case ClassComponent: {
        const instance = finishedWork.stateNode
        if (finishedWork.flags & Update) {
          if (!offscreenSubtreeWasHidden) {
            if (current === null) {
              instance.componentDidMount()
            } else {
              const prevProps
                = finishedWork.elementType === finishedWork.type
                  ? current.memoizedProps
                  : resolveDefaultProps(
                    finishedWork.type,
                    current.memoizedProps
                  )
              const prevState = current.memoizedState
              instance.componentDidUpdate(
                prevProps,
                prevState,
                instance.__reactInternalSnapshotBeforeUpdate
              )
            }
          }
        }
        const updateQueue = finishedWork.updateQueue
        if (updateQueue !== null) {
          // 处理 update 回调函数, e.g: `this.setState({}, callback)`.
          commitUpdateQueue(finishedWork, updateQueue, instance)
        }
        break
      }
      case HostRoot: {
        const updateQueue = finishedWork.updateQueue
        if (updateQueue !== null) {
          let instance = null
          if (finishedWork.child !== null) {
            switch (finishedWork.child.tag) {
              case HostComponent:
                instance = getPublicInstance(finishedWork.child.stateNode)
                break
              case ClassComponent:
                instance = finishedWork.child.stateNode
                break
            }
          }
          // 处理 update 回调函数, e.g: `this.setState({}, callback)`.
          commitUpdateQueue(finishedWork, updateQueue, instance)
        }
        break
      }
      case HostComponent: {
        const instance: Instance = finishedWork.stateNode
        if (current === null && finishedWork.flags & Update) {
          const type = finishedWork.type
          const props = finishedWork.memoizedProps
          commitMount(instance, type, props, finishedWork)
        }
        break
      }
      case SuspenseComponent: {
        commitSuspenseHydrationCallbacks(finishedRoot, finishedWork)
        break
      }
      case HostText:
      case HostPortal:
      case Profiler:
      case SuspenseListComponent:
      case IncompleteClassComponent:
      case ScopeComponent:
      case OffscreenComponent:
      case LegacyHiddenComponent: {
        break
      }
      default:
        throw new Error(
          'This unit of work tag should not have side-effects. This error is '
          + 'likely caused by a bug in React. Please file an issue.'
        )
    }
  }
  // 重新设置ref.
  if (finishedWork.flags & Ref)
    commitAttachRef(finishedWork)
}
Reconciler Performance Tips
- Render: 通过一些启发式算法跳过没有发生变更的子树.
 - Commit:
- 维护了一个列表用于记录变化的 Fiber, 不再访问其他 Fiber.
 - 首次渲染 (Mount) 时只有 
HostRootFiber.flags会设置Placement, 在 Commit 阶段只会执行一次插入操作. 
 - GC:
- Reuse 
OldFiberobjects whenBailout. currentFiber tree andworkInProgressFiber tree forDouble Buffering.
 - Reuse 
 
Minimal Reconciler Implementation
function performWork(deadline) {
  if (!nextUnitOfWork)
    resetNextUnitOfWork()
  // whether current status is idle status or not
  while (nextUnitOfWork && deadline.timeRemaining() > ENOUGH_TIME)
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork)
  if (pendingCommit)
    commitAllWork(pendingCommit)
  // checks if there's pending work
  // if exist, performWork in **next frame** when idle
  if (nextUnitOfWork || updateQueue.length > 0)
    requestIdleCallback(performWork)
}
function scheduleUpdate(instance, partialState) {
  updateQueue.push({
    from: CLASS_COMPONENT,
    instance,
    partialState,
  })
  requestIdleCallback(performWork)
}
// React.render function
function render(elements, container) {
  updateQueue.push({
    from: HOST_ROOT,
    dom: container,
    newProps: {
      children: elements,
    },
  })
  requestIdleCallback(performWork)
}


