React17源码解析(6) —— commit 阶段的实现原理与源码剖析
2023-12-24 06:51:26
前言
React 是一个用于构建用户界面的 JavaScript 库,它使用一种名为“虚拟 DOM”的技术来实现高效的更新。在 React 中,更新过程分为两个阶段:render 阶段和 commit 阶段。在 render 阶段,React 会生成一个新的虚拟 DOM 树,并计算出需要更新的组件。在 commit 阶段,React 会将新的虚拟 DOM 树应用到真实的 DOM 树上。
commit 阶段概述
commit 阶段的执行流程如下:
- React 会调用
commitRoot
函数,该函数会根据新的虚拟 DOM 树更新真实的 DOM 树。 commitRoot
函数会调用commitSyncUnmountStackImpl
函数,该函数会卸载所有需要卸载的组件。commitRoot
函数会调用commitMount
函数,该函数会挂载所有需要挂载的组件。commitRoot
函数会调用commitUpdateQueue
函数,该函数会更新所有需要更新的组件。commitRoot
函数会调用commitLayoutEffects
函数,该函数会执行所有需要执行的布局副作用。
commitRoot 函数
commitRoot
函数是 commit 阶段的核心函数,它负责协调整个 commit 阶段的执行。commitRoot
函数的代码如下:
export function commitRoot(root, finishedWork) {
//省略部分代码
beginWork(finishedWork);
}
commitRoot
函数首先会调用 beginWork
函数,该函数会执行以下三个步骤:
- 将
finishedWork
作为根节点,开始遍历虚拟 DOM 树。 - 在遍历过程中,调用
commitUnmount
函数卸载所有需要卸载的组件。 - 在遍历过程中,调用
commitMount
函数挂载所有需要挂载的组件。
commitUnmount 函数
commitUnmount
函数用于卸载组件,它的代码如下:
function commitUnmount(finishedWork) {
//省略部分代码
if (finishedWork.flags & Placement) {
//省略部分代码
tryUnmount(finishedWork);
}
}
commitUnmount
函数首先会检查组件的 flags
属性,如果 flags
属性包含 Placement
标志,则说明该组件是新创建的组件,尚未挂载到真实的 DOM 树上。因此,commitUnmount
函数会调用 tryUnmount
函数卸载该组件。
commitMount 函数
commitMount
函数用于挂载组件,它的代码如下:
function commitMount(finishedWork) {
//省略部分代码
if (finishedWork.flags & Placement) {
//省略部分代码
insertOrAppendPlacementNode(finishedWork, nextInstance);
}
}
commitMount
函数首先会检查组件的 flags
属性,如果 flags
属性包含 Placement
标志,则说明该组件是新创建的组件,尚未挂载到真实的 DOM 树上。因此,commitMount
函数会调用 insertOrAppendPlacementNode
函数将该组件插入到真实的 DOM 树中。
commitUpdateQueue 函数
commitUpdateQueue
函数用于更新组件,它的代码如下:
function commitUpdateQueue(finishedWork, queue) {
//省略部分代码
const instance = finishedWork.stateNode;
if (queue.flags & Update) {
//省略部分代码
updateQueue.baseState = oldState;
}
}
commitUpdateQueue
函数首先会检查组件的 queue
属性,如果 queue
属性包含 Update
标志,则说明该组件需要更新状态。因此,commitUpdateQueue
函数会调用 updateQueue
函数更新组件的状态。
commitLayoutEffects 函数
commitLayoutEffects
函数用于执行布局副作用,它的代码如下:
function commitLayoutEffects(finishedWork, root, committedNextEffect) {
//省略部分代码
for (const child = finishedWork.firstEffect; child !== null; child = child.nextEffect) {
//省略部分代码
commitEffectUnmount(root, current, committedEffect);
}
}
commitLayoutEffects
函数首先会遍历 finishedWork
的 firstEffect
属性,然后调用 commitEffectUnmount
函数执行卸载副作用。
总结
在本文中,我们介绍了 React17 源码中 commit 阶段的实现原理和源码剖析。我们重点介绍了 commit 阶段中 commitRoot 函数的作用,包括它的执行过程和源码细节。同时,还介绍了 commitRoot 函数是如何处理副作用、更新 DOM 和协调新旧状态的。本文适合对 React 源码和更新过程感兴趣的开发者阅读。