Introduction to the

  • The react version v17.3
  • Only functions, classes, native components.
    • SuspenseComponent OffscreenComponent. Such components are not written.
  • Code simplification
    • Keep only the core logic.
    • **DIFF **reconcileChildrenDo not speak. Know that new fiber will be generated.

The working process

In simple terms, it is depth first traversal (DFS) JSX tree, generating fiber tree. React converts a recursive process into a while loop.

Recurse to the while loop

WorkLoopSync, workLoopConcurrent

  • The while loopworkInProgressPerform performUnitOfWork
    • Each updateworkInProgressFor the newfiber
  • performUnitOfWork
    • beginWork    
  • completeUnitOfWork
    • completeWork    
// Synchronous mode
function workLoopSync() {
  while(workInProgress ! = =null) { performUnitOfWork(workInProgress); }}// ConcurrentMode
function workLoopConcurrent() {
  while(workInProgress ! = =null&&! shouldYield()) { performUnitOfWork(workInProgress); }}Copy the code

Recursive performUnitOfWork

  • Start work => Create a work unitfiber
    • Main Work:childrenJSX= >childrenFiber
      • Why is every job processingchildren ?
        1. diffThe need for new and oldchildrenCompare them.
        2. buildfibersibling returnAnd other information.
        3. dfsRecursive”recursive“Go on. Each updateworkInProgress = childFber
  • And then you end up with a treenewFiberTree
// dfs
function performUnitOfWork(unitOfWork: Fiber) :void {
  const current = unitOfWork.alternate;
  / / pass
  let next = beginWork(current, unitOfWork, subtreeRenderLanes);
  unitOfWork.memoizedProps = unitOfWork.pendingProps;
  if (next === null) {
    / / return
    completeUnitOfWork(unitOfWork);
  } else{ workInProgress = next; }}Copy the code

Return completeUnitOfWork

  • Finish the work =>fiberTree buildinghostTree and render.
    • Main Work:fiber= >instance. Creating host entities
      • How is “return” constructedhostThe tree?
        • Each time will bechildrenFiberinstanceAdded to theworkInProgressinstanceIn the.
      • dfsRecursive”Belong to the“Up, how?
        • fiberAfter completing the completeWork.
          • The new generationworkInProgress
          • Move to thesibling
          • return
  • And finally renderdom
function completeUnitOfWork(unitOfWork: Fiber) :void {
  let completedWork = unitOfWork;
  do {
    const current = completedWork.alternate;
    const returnFiber = completedWork.return;
    let next = completeWork(current, completedWork, subtreeRenderLanes);
    if(next ! = =null) {
      workInProgress = next;
      return;
    }

    const siblingFiber = completedWork.sibling;
    if(siblingFiber ! = =null) {
      // If there is more work to do in this returnFiber, do that next.
      workInProgress = siblingFiber;
      return;
    }
    // Otherwise, return to the parent
    completedWork = returnFiber;
    // Update the next thing we're working on in case something throws.
    workInProgress = completedWork;
  } while(completedWork ! = =null);

  // We've reached the root.
  if(workInProgressRootExitStatus === RootIncomplete) { workInProgressRootExitStatus = RootCompleted; }}Copy the code

Public variables

  • didReceiveUpdate
    • Function: False indicates that sub-fiber does not need update, true indicates that update is required.
    • A function that modifies this value
      • beginWork
      • updateSimpleMemoComponent
      • markWorkInProgressReceivedUpdate()
        • Effect: didReceiveUpdate = true
        • The person who calls this function
          • renderWithHooks
          • renderWithReducer    
          • updateReducer
          • prepareToReadContext
      • bailoutOnAlreadyFinishedWork
  • workInProgress
    • Fiber at work.

beginWork

Create childrenFiber with workinProgress.children (JSX) and return childFiber, the first child.

  • Why is every job processingchildren ?
    1. diffThe need for new and oldchildrenCompare them.
    2. buildfibersibling returnAnd other information.
    3. dfsRecursive”recursive“Go on. Each updateworkInProgress = childFber
  • Logic:
    • judgeworkInProgressIf you needupdate
      • Determine whether there isoldFiber ,
        • Being — judging old and newpropsIs it different,Fiber stack contextWhether to change
          • Props is different
            • Need to update. didReceiveUpdate = false;
          • Whether the same props
            • If no current has interrupted updates.
              • No updates needed. didReceiveUpdate = false;
              • Return Clone Fiber (in other words, alternate, oldFiber)
            • Determine if there isforceUpdateForced to updateflags
              • There are
                • Need to update. didReceiveUpdate = false;
              • There is no
                • No updates needed. didReceiveUpdate = false;
        • Does not exist – means mount
          • No updates needed. didReceiveUpdate = false;
    • workInProgressTask lane is reset to none
    • According to theworkInProgressType of worktagLet’s go to the different work functions
function beginWork(
  current: Fiber | null,
  workInProgress: Fiber,
  renderLanes: Lanes,
) :Fiber | null {
  if(current ! = =null) {
    // update to check whether an update is required
    const oldProps = current.memoizedProps;
    const newProps = workInProgress.pendingProps;
    if( oldProps ! == newProps ||// props is updated if different
      // Force a re-render if the implementation changed due to hot reload:(__DEV__ ? workInProgress.type ! == current.type :false)
    ) {
      didReceiveUpdate = true;
    } else {
      // Check whether the Lane context needs to be updated
      const hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(
        current,
        renderLanes,
      );
      if (
        // No mandatory update! hasScheduledUpdateOrContext && (workInProgress.flags & DidCapture) === NoFlags ) { didReceiveUpdate =false;
        // Clone the old fiber directly
        return attemptEarlyBailoutIfNoScheduledUpdate(
          current,
          workInProgress,
          renderLanes,
        );
      }
      Suspense whether there are mandatory updates
      if((current.flags & ForceUpdateForLegacySuspense) ! == NoFlags) { didReceiveUpdate =true;
      } else {
        didReceiveUpdate = false; }}}else {
    // The mount phase is not updated
    didReceiveUpdate = false;
  }
	// Start work, lane reset
  workInProgress.lanes = NoLanes;

  switch (workInProgress.tag) {
    // The function component mounts with this tag. Modify the tag after the command is executed. For example, components that do not inherit from Component.
    case IndeterminateComponent: {
      return mountIndeterminateComponent(
        current,
        workInProgress,
        workInProgress.type,
        renderLanes,
      );
    }
    // Function components
    case FunctionComponent: {
      const Component = workInProgress.type;
      const unresolvedProps = workInProgress.pendingProps;
      const resolvedProps =
        workInProgress.elementType === Component
          ? unresolvedProps
          : resolveDefaultProps(Component, unresolvedProps);
      return updateFunctionComponent(
        current,
        workInProgress,
        Component,
        resolvedProps,
        renderLanes,
      );
    }
    / / class components
    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,
      );
    }
    // Native component div, etc
    case HostComponent:
      return updateHostComponent(current, workInProgress, renderLanes);
    case HostText:
      return updateHostText(current, workInProgress);
}

Copy the code

Different worker functions tag -> worker functions

The Reconcile Child is a Diff.

HostComponent -> updateHostComponent

Introduction to the

  • Handles native components, as in the browserDOM

function

  • generatechildrenFiber
  • Performance optimization: If the child is a single text node, then the child does not generate fiber.

logic

  • Whether children are single-text nodes
    • A single text
      • Offspring are not generatedfiber. nextChildren = null
    • Not single text
      • ifoldFiberA single text
        • Mark content clearingContentReset
  • markRefWhether the tag is requiredref
  • reconcileChildren diff
  • return workInProgress.child
function updateHostComponent(
  current: Fiber | null,
  workInProgress: Fiber,
  renderLanes: Lanes,
) {
  const type = workInProgress.type;
  const nextProps = workInProgress.pendingProps;
  constprevProps = current ! = =null ? current.memoizedProps : null;
  let nextChildren = nextProps.children;
  Eg 
      
children has only one text node
const isDirectTextChild = shouldSetTextContent(type, nextProps); if (isDirectTextChild) { // The text node does not generate fiber, and the text is rendered directly in commit nextChildren = null; } else if(prevProps ! = =null && shouldSetTextContent(type, prevProps)) { workInProgress.flags |= ContentReset; } markRef(current, workInProgress); reconcileChildren(current, workInProgress, nextChildren, renderLanes); return workInProgress.child; } Copy the code

HostText -> updateHostText

Return NULL without doing anything.

IndeterminateComponent -> mountIndeterminateComponent

Introduction to the

  • functioncomponentmount, take this function. Products left over from history.

function

  • generatechildrenFiber
  • Compatibility: Dealing with old React support factories (factory) function that isFunctionReturn to haveclassObject of a component method.

logic

  • Obtained when the function component executes renderWithHooksvalue
  • judgevalueWhether it is an object that emulates factory Class.
    • isfactory class
      • tagRevised toClassComponent
      • createThe class components
      • return finishClassComponent
    • Whether isFunction component
      • tagRevised toFunctionComponent
      • reconcileChildren
      • return workInProgress.child

function mountIndeterminateComponent(_current, workInProgress, Component, renderLanes,) {
  const props = workInProgress.pendingProps;
  let context;
  // Clear the previous context
  prepareToReadContext(workInProgress, renderLanes);
  // Run the component function
  value = renderWithHooks(
    null,
    workInProgress,
    Component,
    props,
    context,
    renderLanes,
  );
	// Determine whether the function returns a clAS-like object with the render method
  if (
    !disableModulePatternComponents &&
    typeof value === 'object'&& value ! = =null &&
    typeof value.render === 'function' &&
    value.$$typeof === undefined
  ) {
    // Treat this fiber as ClassComponent
    workInProgress.tag = ClassComponent;
    workInProgress.memoizedState = null;
    workInProgress.updateQueue = null;
    let hasContext = false;
    if (isLegacyContextProvider(Component)) {
      hasContext = true;
      pushLegacyContextProvider(workInProgress);
    } else {
      hasContext = false; } workInProgress.memoizedState = value.state ! = =null&& value.state ! = =undefined ? value.state : null;
    initializeUpdateQueue(workInProgress);
    adoptClassInstance(workInProgress, value);
    mountClassInstance(workInProgress, Component, props, renderLanes);
    return finishClassComponent(
      null,
      workInProgress,
      Component,
      true,
      hasContext,
      renderLanes,
    );
  } else {
    // Handle as FunctionComponent
    workInProgress.tag = FunctionComponent;
    // diff
    reconcileChildren(null, workInProgress, value, renderLanes);
    returnworkInProgress.child; }}Copy the code

FunctionComponent -> updateFunctionComponent

Introduction to the

  • functioncomponentupdate, take this function.
  • Build the hooks

function

  • generatechildrenFiber

logic

  • prepareToReadContext
  • RenderWithHooks getnextChildren
  • ifcurrentThere is,didReceiveUpdateflaseNo update is required.
    • bailoutHooks
    • return bailoutOnAlreadyFinishedWork
  • You need to update
  • reconcileChildren
  • return workInProgress.child
function updateFunctionComponent(
  current,
  workInProgress,
  Component,
  nextProps: any,
  renderLanes,
) {
  let context;
  if(! disableLegacyContext) {const unmaskedContext = getUnmaskedContext(workInProgress, Component, true);
    context = getMaskedContext(workInProgress, unmaskedContext);
  }
	
  let nextChildren;
  // Clear the previous context
  prepareToReadContext(workInProgress, renderLanes);
  // Run the component function
  nextChildren = renderWithHooks(
    current,
    workInProgress,
    Component,
    nextProps,
    context,
     renderLanes,
  );
	// Whether an update is required
  if(current ! = =null && !didReceiveUpdate) {
    bailoutHooks(current, workInProgress, renderLanes);
    // Clone the old fiber
    return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
  }
	// diff
  reconcileChildren(current, workInProgress, nextChildren, renderLanes);
  return workInProgress.child;
}

Copy the code

ClassComponent -> updateClassComponent

Introduction to the

  • classThe component uses this function.

function

  • Process the life cycle.
  • generatechildrenFiber

logic

  • PrepareToReadContext – clear context
  • ifmount. fiber.stateNode === null; The stateNode value of the class component is the class instance.
    • constructClassInstance
      • readcontext. readContext
      • Execute constructorconstructor
      • The assignmentstate. fiber.memoizedState = instance.state
    • mountClassInstance
      • fiberInitialize theupdateQueue. initializeUpdateQueue
      • contextAssign values to theinstance.context
      • ** Life cycle **
        • applyDerivedStateFromProps( getDerivedStateFromProps )
          • updateinstance.stateFiber. MemoizedState and ` ` updateQueue baseState
        • If onlycomponentWillMountAnd no newLifecyclesgetDerivedStateFromPropsgetSnapshotBeforeUpdate
          • Perform callComponentWillMount
            • componentWillMount
            • classComponentUpdater.enqueueReplaceState
          • processUpdateQueue
          • updateinstance.state
    • shouldUpdate = true;
  • ifupdate
    • shouldUpdate = updateClassInstance
      • If it had no newLifecyclesexecutecomponentWillReceiveProps  — callComponentWillReceiveProps
        • After execution, ifnewState ! == oldState
          • classComponentUpdater.enqueueReplaceState
            • enqueueUpdate
      • Batch update, calculationnewState. —processUpdateQueue()
        • The assignmentfiber.memoizedState    
        • Ability to handle priorities
      • ** Life cycle **getDerivedStateFromProps()
      • If you need to update
        • ** Life cycle **componentWillUpdate()
      • If it needs to be updated and existscomponentDidUpdate() getSnapshotBeforeUpdate()
        • thefibet.flagswriteUpdate  / Snapshot
      • updatefibet.memoizedProps fiber.memoizedState
      • Class instance update,
        • updateinstaceprops state context
      • return shouldUpdate;
  • finishClassComponent
    • No need to update
      • bailoutOnAlreadyFinishedWork
    • You need to update
      • reconcileChildren
  • return workInProgress.child
function updateClassComponent(
  current: Fiber | null,
  workInProgress: Fiber,
  Component: any,
  nextProps: any,
  renderLanes: Lanes,
) {
  / / to empty the context
  prepareToReadContext(workInProgress, renderLanes);
  const instance = workInProgress.stateNode;
  let shouldUpdate;
  if (instance === null) {
    if(current ! = =null) {
      current.alternate = null;
      workInProgress.alternate = null;
      workInProgress.flags |= Placement;
    }
    // Read the context, execute the constructor, and assign state
    constructClassInstance(workInProgress, Component, nextProps);
    // fiber initializes the updateQueue and assigns the context to the instance
    mountClassInstance(workInProgress, Component, nextProps, renderLanes);
    shouldUpdate = true;
  } else if (current === null) {
    // Reuse the instance
    shouldUpdate = resumeMountClassInstance(
      workInProgress,
      Component,
      nextProps,
      renderLanes,
    );
  } else {
    // Calculate state, execute and update the associated lifecycle
    shouldUpdate = updateClassInstance(
      current,
      workInProgress,
      Component,
      nextProps,
      renderLanes,
    );
  }
  // diff does not need to update, clone
  const nextUnitOfWork = finishClassComponent(
    current,
    workInProgress,
    Component,
    shouldUpdate,
    hasContext,
    renderLanes,
  );
  return nextUnitOfWork;
}
Copy the code

Fragment -> updateFragment

Introduction to the

  • Working with Fragment components
    • PendingProps is childrenJSX

function

  • generatechildrenFiber

logic

  • reconcileChildren
  • return workInProgress.child
function updateFragment(
  current: Fiber | null,
  workInProgress: Fiber,
  renderLanes: Lanes,
) {
  const nextChildren = workInProgress.pendingProps;
  reconcileChildren(current, workInProgress, nextChildren, renderLanes);
  return workInProgress.child;
}
Copy the code

updateHostRoot

Create the react component root.

  • The Reconciler coordinationrootFiberThrough thereconcileChildrenjsxTo buildchildren fiberreturnchild fiber

Logic:

  • fiberRootstate.elementA value ofjsx, i.e.,ReactDOM.renderThe first value in.
  • throughstate.elementreconcileChildren

CompleteWork

Create/update stateNode for workInProgress. Add all the Statenodes for childrenFiber to workinProgress.statenode. SubtreeFlags, childLanes bubbles up. When mount: create DOM, set property update: diff props, create updateQueue Commit.

  • Why allchildthestateNodeAdded to theworkInProgress.stateNodeIn the?
    • Root will eventually form a DOM tree, which can be inserted directly into the DOM tree.
  • Logic:
    • According to theworkInProgressType of worktagEnter different switch blocks
      • The main job is processingHostComponent.
      • Class Function components bubble up onlyflags.lane.bubbleProperties.

Different work functions tag -> switch block

HostComponent

function

  • Create/update the DOM

logic

  • If update.current ! == null && workInProgress.stateNode ! = null   
    • updateHostComponent
      • New and old props will be updated if they differ.
      • workInProgress.updateQueue = prepareUpdate
        • fordomProperties of thediff
        • updatePayload([key,value] array, I for modified attribute, I +1 for modified value)/null
    • The old ref is different from the old ref,
      • markRef
  • If for creating
    • createInstance
      • Create dom
    • appendAllChildren
      • willchildrenFiberstateNodeAdd all toworkInProgress.stateNode
    • finalizeInitialChildren
      • Set properties.
        • Handles the case where the child node is a single text node. setTextContent(domElement, nextProp)
    • markRef
  • bubbleProperties
  • return null
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);
  }
} else {
  // mount dom inserts
  const currentHostContext = getHostContext();
    const instance = createInstance(
      type,
      newProps,
      rootContainerInstance,
      currentHostContext,
      workInProgress,
    );
    appendAllChildren(instance, workInProgress, false.false);
    workInProgress.stateNode = instance;
    if (
      finalizeInitialChildren(instance,type,newProps,rootContainerInstance,currentHostContext,)
    ) {
      markUpdate(workInProgress);
    }
  if(workInProgress.ref ! = =null) {
    markRef(workInProgress);
  }
}
bubbleProperties(workInProgress);
return null;
Copy the code

HostText -> updateHostText

function

  • Create/update the text node

logic

  • If update.current ! == null && workInProgress.stateNode ! = null   
    • updateHostText
      • Mark the Update.
  • If for creating
    • createTextInstance
      • Create a Text node
  • bubbleProperties
  • return null
const newText = newProps;
if(current && workInProgress.stateNode ! =null) {
  const oldText = current.memoizedProps;
  // flags writes update
  updateHostText(current, workInProgress, oldText, newText);
} else {
  const rootContainerInstance = getRootHostContainer();
  const currentHostContext = getHostContext();
  // Create a text node
  workInProgress.stateNode = createTextInstance(
    newText,
    rootContainerInstance,
    currentHostContext,
    workInProgress,
  );
}
Copy the code

bubbleProperties

Fiber attribute subtreeFlags childLanes bubble

  • subtreeFlagsmergechildrentheflagssubtreeFlags
  • childLanesmergechildrenlanechildLane

Each fiber has subtreeFlags and childLanes for its subtrees

CommitRoot

Render the Fiber tree and perform the phases.

  1. To deal withuseEffect.uesLayoutEffect
  2. To deal withclassgetSnapshotBeforeUpdate.componentDidMount.componentDidUpdate.componentWillUnmount
  3. The assignmentref
  4. Execute sequentially (this.setState.ReactDOM.renderThe callback
  5. Modify the view DOM.Placement.Update.Deletion.

Logic:

  • Ideas:
    • Each phase is iteratedroot.finishedWork
      • isrenderPhase completes the construction of the new Fibet tree.
      • Value isroot.current.alternate
    • Each DFS fiber tree, perform the related phase of work
    • Performance optimization:subtreeFlagsAt this stageThe relevantFlagsCompared toNoFlagsThis subtree is skipped

To deal withuseEffect— Attention!! Scheduling, next macro task execution

  • scheduleCallback( flushPassiveEffects )
    • scheduleruseEffectDestroy and create
    • To destroy –commitPassiveUnmountEffects
    • In the create –commitPassiveMountEffects
scheduleCallback(NormalSchedulerPriority, () = > {
  UseEffect destory is executed in create
  flushPassiveEffects();
  return null;
});
Copy the code

BeforMutationStage – before the page changes –commitBeforeMutationEffects

  • Function:
    • DFS Fiber tree, rungetSnapshotBeforeUpdate
  • Logic:
    • commitBeforeMutationEffects_begin
    • commitBeforeMutationEffects_complete
    • commitBeforeMutationEffectsOnFiber
      • performcommitBeforeMutationEffects
      • To deal withSnapshot, i.e.,getSnapshotBeforeUpdate. No other operation is performed temporarily
  • **Mutation**** stage ** — the page is changing —commitMutationEffects
    • Function:
      • DFS Fiber tree, processingDelete  Plcament Update
    • Logic:
      • commitMutationEffects_begin
        • First deal with the deleted fiber
          • iffiber.deletionsExists, then loopDeleteEach fiber
            • Note: Removed fiber is not presentfinishedFiberTreeOnly inreturnFiber.deletions
            • commitDeletion
            • commitNestedUnmounts
              • FunctionComponent : layoutEffect destroy
              • ClassComponent: componentWillUnmount
              • HostConpmentEmpty:ref
            • detachFiberMutation
              • Fiber, alternate return empty
        • commitMutationEffects_complete
        • commitMutationEffectsOnFiber
          • judgeflagsTo perform the work
            • ContentReset

              • Clear text
            • Ref

              • Clearing ref.layout reassigns
            • Visibility
            • Plcament

              • commitPlacement
                • stateNodeinserthost
            • Update

              • commitWork
                • FunctionComponent:layoutEffect destroy
                • HostComponent: Update attributes
                  • commitUpdate updateQueue
                  • Handling Children is an optimization of a single text node
                • HostText: update text
function commitMutationEffects_begin(root: FiberRoot) {
  while(nextEffect ! = =null) {
    const fiber = nextEffect;
    const deletions = fiber.deletions;
    // Deletions does not exist in the finishedWork fiber tree.
    // Because it will not be reused during diff
    if(deletions ! = =null) {
      for (let i = 0; i < deletions.length; i++) {
        const childToDelete = deletions[i];
        // DFS immediately delete fiber
        // function : effect destroy
        // class: componentWillUnmount
        // host: clear ref
        // Then uninstall stateNodecommitDeletion(root, childToDelete, fiber); }}const child = fiber.child;
    // Performance optimization: If there is no task in subtreeFlags, go straight to Fiber, skip subtree, go up "back ",
    if((fiber.subtreeFlags & MutationMask) ! == NoFlags && child ! = =null) {
      nextEffect = child;
    } else {
      // Skip the no task subtree
      // No task subtree or leaf nodecommitMutationEffects_complete(root); }}}function commitMutationEffects_complete(root: FiberRoot) {
  while(nextEffect ! = =null) {
    const fiber = nextEffect;
    commitMutationEffectsOnFiber(fiber, root);
    / / (switch
    const sibling = fiber.sibling;
    if(sibling ! = =null) {
      nextEffect = sibling;
      return;
    }
    Switch / / returnnextEffect = fiber.return; }}function commitMutationEffectsOnFiber(finishedWork: Fiber, root: FiberRoot) {
  const flags = finishedWork.flags;
  if (flags & ContentReset) {
    // Empty the text
    commitResetTextContent(finishedWork);
  }
  if (flags & Ref) {
    const current = finishedWork.alternate;
    / / clear the ref
    if(current ! = =null) { commitDetachRef(current); }}// New features are skipped first
  if (flags & Visibility) {}

  const primaryFlags = flags & (Placement | Update | Hydrating);
  outer: switch (primaryFlags) {
    case Placement: {
      // DOM insert resets the text if there is a Flags ContentReset
      commitPlacement(finishedWork);
      finishedWork.flags &= ~Placement;
      break;
    }
    case PlacementAndUpdate: {
      commitPlacement(finishedWork);
      finishedWork.flags &= ~Placement;
      const current = finishedWork.alternate;
      / / update
      // layoutEffect destroy
      // hostComponent updates properties
      // hostText Updates text
      commitWork(current, finishedWork);
      break;
    }
    case Update: {
      const current = finishedWork.alternate;
      commitWork(current, finishedWork);
      break; }}}Copy the code
  • root.current = finishedWork;
    • When you’re done, switch the tree
    • Why switch here?
      • Before that, the oldfiberTree work depends on
        • Eg:mutationIn the stage ofcomponentWillUnmountIt relies on the old Fiber tree, so it doesn’t switch
      • afterlayoutPhase, eg:componentDidMountandcomponentDidUpdateIt depends on the new Fiber tree, so switch the Fiber tree

Layout stage — after the page changescommitLayoutEffects

  • Function:
    • DFS Fiber tree, processingcomponentDidMountcomponentDidUpdatelayoutEffect createref
      • Callback to perform the setState of class
  • Logic:
    • commitLayoutEffects_begin
      • To deal withOffscreenComponent
    • commitLayoutMountEffects_complete
    • commitLayoutEffectOnFiber
      • commitHookEffectListMount
        • Function:layoutEffect create
        • Class:componentDidUpdate / componentDidMount
          • Judge curren from mount/update
          • performthis.setStateCallback – commitUpdateQueue
        • HostComponent: the Renderer —commitMount
          • The Renderer may need to perform tasks
      • commitAttachRef
        • Update the ref
// DFS with similar Mutation
function commitLayoutEffectOnFiber(
  finishedRoot: FiberRoot,
  current: Fiber | null,
  finishedWork: Fiber,
  committedLanes: Lanes,
) :void {
  if((finishedWork.flags & LayoutMask) ! == NoFlags) {switch (finishedWork.tag) {
      case FunctionComponent: {
        // layoutEffect create
        commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
        break;
      }
      case ClassComponent: {
        const instance = finishedWork.stateNode;
        if (finishedWork.flags & Update) {
            if (current === null) {
              // Life Cycle componentDidMount
              instance.componentDidMount();
            } else {
              const prevProps =
                finishedWork.elementType === finishedWork.type
                  ? current.memoizedProps
                  : resolveDefaultProps(
                    finishedWork.type,
                    current.memoizedProps,
                  );
              const prevState = current.memoizedState;
              // Life Cycle componentDidUpdateinstance.componentDidUpdate( prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate, ); }}const updateQueue = (finishedWork.updateQueue: any);
        if(updateQueue ! = =null) {
          // This. SetState callback queue
          commitUpdateQueue(finishedWork, updateQueue, instance);
        }
        break;
      }
      case HostRoot: {
        const updateQueue: UpdateQueue<*,
          > | null = (finishedWork.updateQueue: any);
        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;
            }
          }
          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;
          // React-dom executes focus after mount
          commitMount(instance, type, props, finishedWork);
        }
        break; }}if (finishedWork.flags & Ref) {
    / / refcommitAttachRef(finishedWork); }}Copy the code
  • commitPhases may generate new tasks for processing.
    • ensureRootIsScheduled
    • flushSyncCallbacks

UseEffect and useLayoutEffect

phase useEffect useLayoutEffect
beforeMutation There is no There is no
mutation There is no Execute deStory (destroy function)
layout There is no Execute create (useLayoutEffect)
Next macro task Run flushPassiveEffects, that is, destory, create There is no

UseLayoutEffect is executed synchronously. UseEffect is executed asynchronously after a commit