关于javascript:React-before-mutation阶段

45次阅读

共计 4377 个字符,预计需要花费 11 分钟才能阅读完成。

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.',
  );
}

新版生命周期。

总结

这节次要学习 before mutation 阶段函数调用流程

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

正文完
 0