关于javascript:React源码Part8CommitLayout阶段

38次阅读

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

React 中双缓存机制触发——Current 指针替换

  • 产生工夫点是: 在 commit 阶段中的 Mutation 阶段之后,Layout 阶段之前
  • 起因一 :在 Mutation 阶段时,会执行 componentWillUnMount 生面周期,此时可能会操作原来 Fibre 节点的内容;为确保数据的可靠性所以不会批改 Current 指针
  • 起因三: Mutation 阶段实现后,此时曾经实现 WorkInProgress 中 Fibre 树的渲染
  • 起因二 :在 Layout 阶段会执行 ComponentDidMount、ComponentDidUpdate 生命周期;为确保数据的污浊和更新,所以在 Layout 阶段之前发替换 Current 指针。

Commit 中的 Layout 阶段的执行过程?

  • 入口函数:commitLayoutEffects
  • 筹备工作:commitLayoutEffects_begin
  • 预处理:commitLayoutMountEffects_complete
    1. 对于函数组件 Hook,useLayoutEffect 的回调函数在这里执行
  • 对 Fibre 节点进行解决:commitLayoutEffectOnFiber

    1. 对于 Class 组件,componentDidMount 和 componentDidUpdate 生命周期触发

Commit 中的 Layout 阶段做了什么?

  • 对于 Class 组件而言, 在这个阶段会执行 ComponentDidMount、ComponentDidUpdate 生命周期
  • 对于函数组建 Hook 而言, 会执行 useLayoutEffect 的回调函数 (不包含返回值)

    1. 对于上面这个 useEffect,会在 Layout 阶段执行 handleStatusChange 函数 (create);在 Mutation 阶段执行 useEffect 返回的函数 (destroy),用于清理副作用

       useEffect(() => {function handleStatusChange(status) {setIsOnline(status.isOnline);
        }
       
        return () => {ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
        };
      });

commitLayoutEffects——入口函数

export function commitLayoutEffects(
  finishedWork: Fiber,
  root: FiberRoot,
  committedLanes: Lanes,
): void {
  inProgressLanes = committedLanes;
  inProgressRoot = root;
  nextEffect = finishedWork;

  commitLayoutEffects_begin(finishedWork, root, committedLanes);

  inProgressLanes = null;
  inProgressRoot = null;
}

commitLayoutEffects_begin——筹备工作

commitLayoutMountEffects_complete——预处理

  • 执行 useLayoutEffect 的回调函数 safelyCallCommitHookLayoutEffectListMount

    1. 能够在 switch 语句汇总看到,case 条件是 SimpleMemoComponent

  • commitLayoutMountEffects_complete 代码片段

    function commitLayoutMountEffects_complete(
    subtreeRoot: Fiber,
    root: FiberRoot,
    committedLanes: Lanes,
    ) {
    // Suspense layout effects semantics don't change for legacy roots.
    const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;
    
    while (nextEffect !== null) {
      const fiber = nextEffect;
    
      if (
        enableSuspenseLayoutEffectSemantics &&
        isModernRoot &&
        offscreenSubtreeWasHidden &&
        !offscreenSubtreeIsHidden
      ) {
        // Inside of an Offscreen subtree that changed visibility during this commit.
        // If this subtree was hidden, layout effects will have already been destroyed (during mutation phase)
        // but if it was just shown, we need to (re)create the effects now.
        // TODO (Offscreen) Check: flags & LayoutStatic
        switch (fiber.tag) {
          case FunctionComponent:
          case ForwardRef:
          case SimpleMemoComponent: {
            if (
              enableProfilerTimer &&
              enableProfilerCommitHooks &&
              fiber.mode & ProfileMode
            ) {
              try {startLayoutEffectTimer();
                safelyCallCommitHookLayoutEffectListMount(fiber, fiber.return);
              } finally {recordLayoutEffectDuration(fiber);
              }
            } else {safelyCallCommitHookLayoutEffectListMount(fiber, fiber.return);
            }
            break;
          }
          case ClassComponent: {
            const instance = fiber.stateNode;
            if (typeof instance.componentDidMount === 'function') {safelyCallComponentDidMount(fiber, fiber.return, instance);
            }
            break;
          }
        }
    
        // TODO (Offscreen) Check flags & RefStatic
        switch (fiber.tag) {
          case ClassComponent:
          case HostComponent:
            safelyAttachRef(fiber, fiber.return);
            break;
        }
      } else if ((fiber.flags & LayoutMask) !== NoFlags) {
        const current = fiber.alternate;
        if (__DEV__) {// DEV 环境能够临时不论} else {
          try {commitLayoutEffectOnFiber(root, current, fiber, committedLanes);
          } catch (error) {captureCommitPhaseError(fiber, fiber.return, error);
          }
        }
      }
    
      if (fiber === subtreeRoot) {
        nextEffect = null;
        return;
      }
    
      const sibling = fiber.sibling;
      if (sibling !== null) {ensureCorrectReturnPointer(sibling, fiber.return);
        nextEffect = sibling;
        return;
      }
    
      nextEffect = fiber.return;
    }
    }

commitLayoutEffectOnFiber——解决 Fibre 节点

  • Class 组件的生命周期 componentDidMount 和 componentDidUpdate 生命周期在此触发,触发条件就是以后的 current 指针是 null
  • componentDidMount 生命周期执行片段
  • componentDidUpdate 生命周期执行片段

正文完
 0