react 源码解析 10.commit 阶段
react 源码解析 10.commit 阶段
视频讲解(高效学习):进入学习
往期文章:
在 render 阶段的末尾会调用 commitRoot(root);进入 commit 阶段,这里的 root 指的就是 fiberRoot,然后会遍历 render 阶段生成的 effectList,effectList 上的 Fiber 节点保存着对应的 props 变化。之后会遍历 effectList 进行对应的 dom 操作和生命周期、hooks 回调或销毁函数,各个函数做的事情如下
在 commitRoot 函数中其实是调度了 commitRootImpl 函数
在 commitRootImpl 的函数中主要分三个部分:
commit 阶段前置工作
调用 flushPassiveEffects 执行完所有 effect 的任务
初始化相关变量
赋值 firstEffect 给后面遍历 effectList 用
mutation 阶段
遍历 effectList 分别执行三个方法 commitBeforeMutationEffects、commitMutationEffects、commitLayoutEffects 执行对应的 dom 操作和生命周期
在介绍双缓存 Fiber 树的时候,我们在构建完 workInProgress Fiber 树之后会将 fiberRoot 的 current 指向 workInProgress Fiber,让 workInProgress Fiber 成为 current,这个步骤发生在 commitMutationEffects 函数执行之后,commitLayoutEffects 之前,因为 componentWillUnmount 发生在 commitMutationEffects 函数中,这时还可以获取之前的 Update,而 componentDidMount
和
componentDidUpdate 会在 commitLayoutEffects 中执行,这时已经可以获取更新后的真实 dom 了
mutation 后
根据 rootDoesHavePassiveEffects 赋值相关变量
执行 flushSyncCallbackQueue 处理 componentDidMount 等生命周期或者 useLayoutEffect 等同步任务
现在让我们来看看 mutation 阶段的三个函数分别做了什么事情
commitBeforeMutationEffects 该函数主要做了如下两件事
执行 getSnapshotBeforeUpdate 在源码中 commitBeforeMutationEffectOnFiber 对应的函数是 commitBeforeMutationLifeCycles 在该函数中会调用 getSnapshotBeforeUpdate,现在我们知道了 getSnapshotBeforeUpdate 是在 mutation 阶段中的 commitBeforeMutationEffect 函数中执行的,而 commit 阶段是同步的,所以 getSnapshotBeforeUpdate 也同步执行
调度 useEffect
在 flushPassiveEffects 函数中调用 flushPassiveEffectsImpl 遍历 pendingPassiveHookEffectsUnmount 和 pendingPassiveHookEffectsMount,执行对应的 effect 回调和销毁函数,而这两个数组是在 commitLayoutEffects 函数中赋值的(待会就会讲到),mutation 后 effectList 赋值给 rootWithPendingPassiveEffects,然后 scheduleCallback 调度执行 flushPassiveEffects
commitMutationEffectscommitMutationEffects 主要做了如下几件事
调用 commitDetachRef 解绑 ref(第 11 章 hook 会讲解)
根据 effectTag 执行对应的 dom 操作
useLayoutEffect 销毁函数在 UpdateTag 时执行
commitLayoutEffects 在 commitMutationEffects 之后所有的 dom 操作都已经完成,可以访问 dom 了,commitLayoutEffects 主要做了
调用 commitLayoutEffectOnFiber 执行相关生命周期函数或者 hook 相关 callback
执行 commitAttachRef 为 ref 赋值
评论