React源码Part6——Commit阶段(beforeMutation)

Posted 冷咖啡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React源码Part6——Commit阶段(beforeMutation)相关的知识,希望对你有一定的参考价值。

React源码Part-1——代数效应:https://segmentfault.com/a/11...
React源码Part2——渲染原理: https://segmentfault.com/a/11...
React源码Part3——Fiber架构:https://segmentfault.com/a/11...
React源码Part4——Render渲染(Mount阶段):https://segmentfault.com/a/11...
React源码Part4——Render渲染(Update阶段):https://segmentfault.com/a/11...
React源码Part5——commit阶段(处理class组件生命周期): https://segmentfault.com/a/11...
React源码Part7——Commit(Mutation阶段): https://segmentfault.com/a/11...
React源码Part8——Commit(Layout阶段):https://segmentfault.com/a/11...
参考链接:React技术揭秘——https://react.iamkasong.com/p...

beforeMutaion阶段做了什么

  • 第一步__入口函数:commitBeforeMutationEffects()
  • 第二步__开始处理Effects链表的单个Fiber节点:commitBeforeMutationEffects_begin()
  • 第三步__遍历Effects链表中每个fiebr节点:commitBeforeMutationEffects_complete()
  • 第四步__处理得到的单个Fibre节点:commitBeforeMutationEffectsOnFiber()

commitBeforeMutationEffects()

export function commitBeforeMutationEffects(
  root: FiberRoot,
  firstChild: Fiber,
) {
  focusedInstanceHandle = prepareForCommit(root.containerInfo);

  // 链表结构的 nextEffect 
  nextEffect = firstChild;
  // 开始执行 BeforeMutationEffects
  commitBeforeMutationEffects_begin();

  // We no longer need to track the active instance fiber
  const shouldFire = shouldFireAfterActiveInstanceBlur;
  shouldFireAfterActiveInstanceBlur = false;
  focusedInstanceHandle = null;

  return shouldFire;
}

commitBeforeMutationEffects_begin()

function commitBeforeMutationEffects_begin() {
  // 如果有需要处理的Effect
  while (nextEffect !== null) {
    const fiber = nextEffect;

    // TODO: Should wrap this in flags check, too, as optimization
    // 给需要处理的Fiber搭上标记
    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
    ) {
      // 处理Fibre节点的兄弟节点——这是调度相关
      ensureCorrectReturnPointer(child, fiber);
      nextEffect = child;
    } else {
      // 处理单个的Fibre节点
      commitBeforeMutationEffects_complete();
    }
  }
}

commitBeforeMutationEffects_complete()

function commitBeforeMutationEffects_complete() {
  while (nextEffect !== null) {
    const fiber = nextEffect;
    if (__DEV__) {
      // DEV 环境的东西可以不管
      // ...

    } else {
      try {
        // 处理从Effect链表得到的单个Fiber节点
        commitBeforeMutationEffectsOnFiber(fiber);
      } catch (error) {
        captureCommitPhaseError(fiber, fiber.return, error);
      }
    }

    const sibling = fiber.sibling;
    // 处理兄弟节点的Fiber
    if (sibling !== null) {
      ensureCorrectReturnPointer(sibling, fiber.return);
      nextEffect = sibling;
      return;
    }

    nextEffect = fiber.return;
  }
}

commitBeforeMutationEffectsOnFiber()

function commitBeforeMutationEffectsOnFiber(finishedWork: Fiber) {
  const current = finishedWork.alternate;
  const flags = finishedWork.flags;

  if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {
    // Check to see if the focused element was inside of a hidden (Suspense) subtree.
    // TODO: Move this out of the hot path using a dedicated effect tag.
    if (
      finishedWork.tag === SuspenseComponent &&
      isSuspenseBoundaryBeingHidden(current, finishedWork) &&
      doesFiberContain(finishedWork, focusedInstanceHandle)
    ) {
      shouldFireAfterActiveInstanceBlur = true;
      beforeActiveInstanceBlur(finishedWork);
    }
  }

  if ((flags & Snapshot) !== NoFlags) {
    setCurrentDebugFiberInDEV(finishedWork);

    // 根据不同的tag处理对应的事件,
    switch (finishedWork.tag) {
      case FunctionComponent:
      case ForwardRef:
      case SimpleMemoComponent: {
        break;
      }
      case ClassComponent: {
        if (current !== null) {
          const prevProps = current.memoizedProps;
          const prevState = current.memoizedState;
          const instance = finishedWork.stateNode;
          
          // 对于class组件而言,getSnaoshotBeforeUpdat生命周期在此调用
          const snapshot = instance.getSnapshotBeforeUpdate(
            finishedWork.elementType === finishedWork.type
              ? prevProps
              : resolveDefaultProps(finishedWork.type, prevProps),
            prevState,
          );
          instance.__reactInternalSnapshotBeforeUpdate = snapshot;
        }
        break;
      }
      
      // 对于函数组件(Hooks)而言,执行的内容
      case HostRoot: {
        if (supportsMutation) {
          const root = finishedWork.stateNode;
          clearContainer(root.containerInfo);
        }
        break;
      }
      case HostComponent:
      case HostText:
      case HostPortal:
      case IncompleteClassComponent:
        // Nothing to do for these component types
        break;
      default: {
        invariant(
          false,
          \'This unit of work tag should not have side-effects. This error is \' +
            \'likely caused by a bug in React. Please file an issue.\',
        );
      }
    }

    resetCurrentDebugFiberInDEV();
  }
}

以上是关于React源码Part6——Commit阶段(beforeMutation)的主要内容,如果未能解决你的问题,请参考以下文章

react源码学习-架构篇-commit阶段

react源码debugger-commit阶段的完成

react源码debugger-commit阶段的完成

自顶而下学习react源码 架构篇 commit阶段

react源码学习-架构篇-render阶段

自顶而下学习react源码 架构篇 render阶段