共计 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
- 对于 Class 组件,componentDidMount 和 componentDidUpdate 生命周期触发
Commit 中的 Layout 阶段做了什么?
- 对于 Class 组件而言, 在这个阶段会执行 ComponentDidMount、ComponentDidUpdate 生命周期
-
对于函数组建 Hook 而言, 会执行 useLayoutEffect 的回调函数 (不包含返回值)
-
对于上面这个 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
- 能够在 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 生命周期执行片段
正文完
发表至: javascript
2021-06-03