React源码Part-1——代数效应:https://segmentfault.com/a/11...
React源码Part2——渲染原理: https://segmentfault.com/a/11...
React源码Part3——Fiber架构:https://segmentfault.com/a/11...
React源码Part4——Render渲染(Mount阶段):https://segmentfault.com/a/11...
React源码Part4——Render渲染(Update阶段):https://segmentfault.com/a/11...
React源码Part5——commit阶段(处理class组件生命周期): https://segmentfault.com/a/11...
React源码Part6——Commit阶段(beforeMutation):https://segmentfault.com/a/11...
React源码Part7——Commit(Mutation阶段): https://segmentfault.com/a/11...
参考链接:React技术揭秘——https://react.iamkasong.com/p...
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生命周期执行片段
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。