早睡wqi

V1

2022/04/10阅读:16主题:默认主题

React before mutation阶段

commit阶段分为三个部分

  • before mutation阶段
  • mutation阶段
  • layout阶段 主要都是在commitRootImpl函数内进行调用

commitRootImpl

这里只展示调用before mutation阶段的代码

if (firstEffect !== null) {
  // 保存之前的优先级,以同步优先级执行,执行完毕后恢复之前优先级
  const previousLanePriority = getCurrentUpdateLanePriority();
  setCurrentUpdateLanePriority(SyncLanePriority);

 // 将当前上下文标记为CommitContext,作为commit阶段的标志
  const prevExecutionContext = executionContext;
  executionContext |= CommitContext;
  const prevInteractions = pushInteractions(root);

  // 在调用生命周期之前将此重置为 null
  ReactCurrentOwner.current = null;

  // The commit phase is broken into several sub-phases. We do a separate pass
  // of the effect list for each phase: all mutation effects come before all
  // layout effects, and so on.

  // The first phase a "before mutation" phase. We use this phase to read the
  // state of the host tree right before we mutate it. This is where
  // getSnapshotBeforeUpdate is called.
  focusedInstanceHandle = prepareForCommit(root.containerInfo);
  shouldFireAfterActiveInstanceBlur = false;

  nextEffect = firstEffect;
  do {
    if (__DEV__) {
      //....开发环境下调用
      invokeGuardedCallback(null, commitBeforeMutationEffects, null);
      if (hasCaughtError()) {
        invariant(nextEffect !== null'Should be working on an effect.');
        const error = clearCaughtError();
        captureCommitPhaseError(nextEffect, error);
        nextEffect = nextEffect.nextEffect;
      }
    } else {
      try {
        // 调用commitBeforeMutationEffects
        commitBeforeMutationEffects();
      } catch (error) {
        invariant(nextEffect !== null'Should be working on an effect.');
        captureCommitPhaseError(nextEffect, error);
        nextEffect = nextEffect.nextEffect;
      }
    }
  } while (nextEffect !== null);
  //....
}

invokeGuardedCallback

开发环境下调用commitBeforeMutationEffects函数

function invokeGuardedCallback(name, func, context, a, b, c, d, e, f{
  hasError = false;
  caughtError = null;
  invokeGuardedCallbackImpl$1.apply(reporter, arguments);
}

commitBeforeMutationEffects

调用before mutation主要函数

function commitBeforeMutationEffects({
  while (nextEffect !== null) {
    const current = nextEffect.alternate;

    if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {
      // ...focus blur相关
      if ((nextEffect.effectTag & Deletion) !== NoEffect) {
        if (doesFiberContain(nextEffect, focusedInstanceHandle)) {
          shouldFireAfterActiveInstanceBlur = true;
          beforeActiveInstanceBlur();
        }
      } else {
        // TODO: Move this out of the hot path using a dedicated effect tag.
        if (
          nextEffect.tag === SuspenseComponent &&
          isSuspenseBoundaryBeingHidden(current, nextEffect) &&
          doesFiberContain(nextEffect, focusedInstanceHandle)
        ) {
          shouldFireAfterActiveInstanceBlur = true;
          beforeActiveInstanceBlur();
        }
      }
    }

    const effectTag = nextEffect.effectTag;
    if ((effectTag & Snapshot) !== NoEffect) {
      setCurrentDebugFiberInDEV(nextEffect);
   // 调用getSnapshotBeforeUpdate
      commitBeforeMutationEffectOnFiber(current, nextEffect);

      resetCurrentDebugFiberInDEV();
    }
    // 调度useEffect
    if ((effectTag & Passive) !== NoEffect) {
      // If there are passive effects, schedule a callback to flush at
      // the earliest opportunity.
      if (!rootDoesHavePassiveEffects) {
        rootDoesHavePassiveEffects = true;
        scheduleCallback(NormalSchedulerPriority, () => {
          flushPassiveEffects();
          return null;
        });
      }
    }
    nextEffect = nextEffect.nextEffect;
  }
}

commitBeforeMutationEffectOnFiber

主要判断组件类型,如果是类组件就执行getSnapshotBeforeUpdate生命周期

function commitBeforeMutationLifeCycles(
  current: Fiber | null,
  finishedWork: Fiber,
): void 
{
  switch (finishedWork.tag) {
    case FunctionComponent:
    case ForwardRef:
    case SimpleMemoComponent:
    case Block: {
      return;
    }
    case ClassComponent: {
      if (finishedWork.effectTag & Snapshot) {
        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.
          // TODO: revisit this when we implement resuming.
          if (__DEV__) {
            // ....
          }
          // 调用getSnapshotBeforeUpdate生命周期
          const snapshot = instance.getSnapshotBeforeUpdate(
            finishedWork.elementType === finishedWork.type
              ? prevProps
              : resolveDefaultProps(finishedWork.type, prevProps),
            prevState,
          );
          if (__DEV__) {
            // ....
          }
          instance.__reactInternalSnapshotBeforeUpdate = snapshot;
        }
      }
      return;
    }
    case HostRoot: {
      if (supportsMutation) {
        if (finishedWork.effectTag & Snapshot) {
          const root = finishedWork.stateNode;
          clearContainer(root.containerInfo);
        }
      }
      return;
    }
    case HostComponent:
    case HostText:
    case HostPortal:
    case IncompleteClassComponent:
      // Nothing to do for these component types
      return;
  }
  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.',
  );
}

新版生命周期。[1] 生命周期

总结 这节主要学习before mutation阶段函数调用流程

  • commitRootImpl是commit阶段主要函数,调用commitBeforeMutationEffects
  • commitBeforeMutationEffects主要功能是:执行commitBeforeMutationEffectOnFiber和通过flushPassiveEffects调度useEffect
  • commitBeforeMutationEffectOnFiber通过判断组件类型主要来执行类组件getSnapshotBeforeUpdate生命周期函数
before mutation阶段调用
before mutation阶段调用

参考资料

[1]

深入详解React生命周期: https://juejin.cn/post/6914112105964634119.

分类:

前端

标签:

React.js

作者介绍

早睡wqi
V1