Skip to content

commitBeforeMutationEffects

Commit阶段对于副作用的第一次遍历处理过程。

在这个阶段每一个FiberNode对应的DOM元素已经生成,但是没有插入到浏览器中(保存在内存中),

其主要作用如下:

  1. 组件的Blur事件
  2. 处理 Class组件 getSnapshotBeforeUpdate() 生命周期方法副作用
  3. 处理 useEffect 类型的 effect 副作用

处理 Class组件 getSnapshotBeforeUpdate() 生命周期方法副作用

这个过程具体的方法为 commitBeforeMutationLifeCycles(current, finishedWork )

js

/**
 * Commit阶段 在DOM插入浏览器之前 触发生命周期函数
 *  - 回调 Class组件 getSnapshotBeforeUpdate() 生命周期方法副作用
 *  - HostRoot 清除根节点的子元素 div#root 下的元素
 * @param {*} current
 * @param {*} finishedWork
 * @returns
 */
function commitBeforeMutationLifeCycles(
  current: Fiber | null,
  finishedWork: Fiber,
): void {
  switch (finishedWork.tag) {
    case FunctionComponent:
    case ForwardRef:
    case SimpleMemoComponent:
    case Block: {
      return;
    }
    case ClassComponent: {
      if (finishedWork.flags & Snapshot) {
        if (current !== null) {
          const prevProps = current.memoizedProps;
          const prevState = current.memoizedState;
          const instance = finishedWork.stateNode;
          // 触发 getSnapshotBeforeUpdate(prevProps, prevState)
          // prevProps 之前的props
          // 之前的 state
          const snapshot = instance.getSnapshotBeforeUpdate(
            finishedWork.elementType === finishedWork.type
              ? prevProps
              : resolveDefaultProps(finishedWork.type, prevProps),
            prevState,
          );
     
          instance.__reactInternalSnapshotBeforeUpdate = snapshot;
        }
      }
      return;
    }
    case HostRoot: {
      if (supportsMutation) {
        if (finishedWork.flags & Snapshot) {
          const root = finishedWork.stateNode;
          // 清空跟节点DOM元素div#root下的子元素
          clearContainer(root.containerInfo);
        }
      }
      return;
    }
    case HostComponent:
    case HostText:
    case HostPortal:
    case IncompleteClassComponent:
      // Nothing to do for these component types
      return;
  }
}

可以看到其核心就是调用class组件的getSnapshotBeforeUpdate生命周期方法

getSnapshotBeforeUpdate()

在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期方法的任何返回值将作为参数传递给 componentDidUpdate()

处理 useEffect 类型的 effect 副作用

image

这是官网对于useEffect的解释,具体功能放到useEffect讲解

我们这边主要说的是在这个过程中,会将useEffect类型的副作用放到任务队列中去

js
    // 处理 useEffect 类型的 effect
    // 主要是将其放到任务队列中去
    if ((flags & Passive) !== NoFlags) {
      // If there are passive effects, schedule a callback to flush at
      // the earliest opportunity.
      if (!rootDoesHavePassiveEffects) {
        rootDoesHavePassiveEffects = true;
        scheduleCallback(NormalSchedulerPriority, () => {
          flushPassiveEffects();
          return null;
        });
      }
    }