React commit阶段解析-前置学习
在renderRootSync执行完render相关阶段后,就会进入commit阶段。performSyncWorkOnRoot函数执行的末尾调用commitRoot(root);
commit阶段工作
在 rootFiber.firstEffect 上保存了一条需要执行副作用的 Fiber 节点的单向链表effectList,这些 Fiber 节点的 updateQueue 中保存了变化的 props。【React commit阶段解析-前置学习】这些副作用对应的 DOM 操作在commit 阶段执行。
除此之外,一些生命周期钩子(比如 componentDidXXX)、hook(比如 useEffect)需要在commit 阶段执行。
commit 阶段的主要工作分为三部分:
- before mutation 阶段(执行 DOM 操作前)
- mutation 阶段(执行 DOM 操作)
- layout 阶段(执行 DOM 操作后)
function commitRoot(root) {
// getCurrentPriorityLevel调度优先级相关
const renderPriorityLevel = getCurrentPriorityLevel();
runWithPriority(
ImmediateSchedulerPriority,
commitRootImpl.bind(null, root, renderPriorityLevel),
);
return null;
}
commitRootImpl 代码300多行, 主要包括commit的前置工作和上文三阶段的执行,下面代码主要是前置部分
commit阶段前置工作:
- 调用flushPassiveEffects执行完所有effect的任务
- 初始化相关变量
- 赋值firstEffect给后面遍历effectList用
function commitRootImpl(root, renderPriorityLevel) { do { // 触发 useEffect 回调与其他同步任务。由于这些任务可能触发新的渲染,所以这里要一直遍历执行直到没有任务 flushPassiveEffects(); } while (rootWithPendingPassiveEffects !== null); // 指向当前应用的rootFiber const finishedWork = root.finishedWork; // 优先级 const lanes = root.finishedLanes; if (finishedWork === null) { return null; } // 重置变量 root.finishedWork = null; root.finishedLanes = NoLanes; // Scheduler回调函数重置 root.callbackNode = null; root.callbackId = NoLanes; // 合并和清除优先级 let remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes); markRootFinished(root, remainingLanes); // 清除已完成的discrete updates,例如:用户鼠标点击触发的更新。 if (rootsWithPendingDiscreteUpdates !== null) { if ( !hasDiscreteLanes(remainingLanes) && rootsWithPendingDiscreteUpdates.has(root) ) { rootsWithPendingDiscreteUpdates.delete(root); } }// 重置全局变量 if (root === workInProgressRoot) { workInProgressRoot = null; workInProgress = null; workInProgressRootRenderLanes = NoLanes; } else { }// 将effectList副作用赋值给firstEffect let firstEffect; if (finishedWork.effectTag > PerformedWork) { if (finishedWork.lastEffect !== null) { finishedWork.lastEffect.nextEffect = finishedWork; firstEffect = finishedWork.firstEffect; } else { firstEffect = finishedWork; } } else { firstEffect = finishedWork.firstEffect; } }
function flushPassiveEffects() {
if (pendingPassiveEffectsRenderPriority !== NoSchedulerPriority) {
const priorityLevel =
pendingPassiveEffectsRenderPriority > NormalSchedulerPriority
? NormalSchedulerPriority
: pendingPassiveEffectsRenderPriority;
pendingPassiveEffectsRenderPriority = NoSchedulerPriority;
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(
schedulerPriorityToLanePriority(priorityLevel),
);
return runWithPriority(priorityLevel, flushPassiveEffectsImpl);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
}
}
}
总结
- 这一章主要看了commitRootImpl函数部分代码
- 了解commmit阶段的前置工作
- 了解到有三个不一样的函数执行流程:
- before mutation 阶段(执行 DOM 操作前)
- mutation 阶段(执行 DOM 操作)
- layout 阶段(执行 DOM 操作后)
推荐阅读
- 结营啦!
- react|react 安装
- 第二阶段day1总结
- 活的教导7:两个阶段
- React.js学习笔记(17)|React.js学习笔记(17) Mobx
- React.js的表单(六)
- 鼎典书画|鼎典书画 | 《章法阶段练习》
- 【React|【React Native填坑之旅】从源码角度看JavaModule注册及重载陷阱
- react-navigation|react-navigation 动态修改 tabBar 样式
- Flutter|Flutter SwiftUI React 对比