本文仅仅是阅读 图解 React 原理系列 的笔记,了解更多内容请查看原文链接。

概览

Fiber 树渲染阶段被称为 commit 阶段。fiberNode 阶段流程可能被打断,而 commit 阶段一旦开始就会同步执行直到完成。

整个阶段可以分为三个子阶段:

  • BeforeMutation 阶段
  • Mutation 阶段
  • Layout 阶段

CommitRoot

整个渲染逻辑都在 CommitRootImpl 函数上,其源码位置 ReactFiberWorkLoop.new.js

在 commitRoot 中同时使用到了渲染优先级和调度优先级,最后的实现是通过 commitRootImpl 函数:

function commitRootImpl(root, recoverableErrors, transitions, renderPriorityLevel) {
  // ============
  // 渲染前准备
  // ============
  const finishedWork = root.finishedWork;
  const lanes = root.finishedLanes;

  // 清空 FiberRoot 对象上的属性
  root.finishedWork = null;
  root.finishedLanes = NoLanes;
  root.callbackNode = null;

  if (root === workInProgressRoot) {
    workInProgressRoot = null;
    workInProgress = null;
    workInProgressRootRenderLanes = NoLanes;
  }

  // ========
  // 渲染
  // ========
  // 检查是否有副作用在整个树
  const subtreeHasEffect =
    (finishedWork.subtreeFlags & (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==
    NoFlags;
  const rootHasEffect =
    (finishedWork.flags & (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==
    NoFlags;

  if (subtreeHasEffect || rootHasEffect) {
    const prevExecutionContext = executionContext;
    executionContext |= CommitContext;
    const prevInteractions = pushInteractions(root);

    // 调用生命周期前,重置为null
    ReactCurrentOwner.current = null;

    // 第一个阶段
    commitBeforeMutationEffects(finishedWork);

    // 第二个阶段
    commitMutationEffects(finishedWork, root, renderPriorityLevel);

    // fiber 树的切换
    root.current = finishedWork;

    // 第三个阶段
    commitLayoutEffects(finishedWork, root, lanes);

    // 如果有被动的副作用,调度一个回调处理它。
    if (
      (finishedWork.subtreeFlags & PassiveMask) !== NoFlags ||
      (finishedWork.flags & PassiveMask) !== NoFlags
    ) {
      if (!rootDoesHavePassiveEffects) {
        rootDoesHavePassiveEffects = true;
        scheduleCallback(NormalSchedulerPriority, () => {
          flushPassiveEffecs();
          return null;
        });
      }
    }

    // 告知调度器在帧的末尾产生,所以浏览器能有机会绘制。
    requestPaint();

    // =========
    // 渲染后
    // =========
    const rootDidHavePassiveEffects = rootDoesHavePassiveEffects;

    if (rootDoesHavePassiveEffects) {
      // 这次 commit 有被动副作用,保存对它们的引用。
      rootDoesHavePassiveEffects = false;
      rootWithPendingPassiveEffects = root;
      pendingPassiveEffectsLanes = lanes;
    } else {
      releaseRootPooledCache(root, remainingLanes);
    }

    // 结束之前总是要调用该函数,确保当前 root 所有额外的工作的被调度。
    ensureRootIsScheduled(root, now());

    // 如果布局被调度了,刷新它
    flushSyncCallbackQueue();

    return null;
  }
}

大致可以将 commitRootImpl 划分为渲染前,渲染,渲染后。

渲染前主要是设置一些全局变量和重置一些全局状态。

渲染被划分为 3 个阶段处理实现:

  • commitBeforeMutationEffects
  • commitMutationEffects
  • recursivelyCommitLayoutEffects

渲染后主要做一些重置和清理工作。

参考链接