返回

React17源码解析(6) —— commit 阶段的实现原理与源码剖析

前端

前言

React 是一个用于构建用户界面的 JavaScript 库,它使用一种名为“虚拟 DOM”的技术来实现高效的更新。在 React 中,更新过程分为两个阶段:render 阶段和 commit 阶段。在 render 阶段,React 会生成一个新的虚拟 DOM 树,并计算出需要更新的组件。在 commit 阶段,React 会将新的虚拟 DOM 树应用到真实的 DOM 树上。

commit 阶段概述

commit 阶段的执行流程如下:

  1. React 会调用 commitRoot 函数,该函数会根据新的虚拟 DOM 树更新真实的 DOM 树。
  2. commitRoot 函数会调用 commitSyncUnmountStackImpl 函数,该函数会卸载所有需要卸载的组件。
  3. commitRoot 函数会调用 commitMount 函数,该函数会挂载所有需要挂载的组件。
  4. commitRoot 函数会调用 commitUpdateQueue 函数,该函数会更新所有需要更新的组件。
  5. commitRoot 函数会调用 commitLayoutEffects 函数,该函数会执行所有需要执行的布局副作用。

commitRoot 函数

commitRoot 函数是 commit 阶段的核心函数,它负责协调整个 commit 阶段的执行。commitRoot 函数的代码如下:

export function commitRoot(root, finishedWork) {
  //省略部分代码

  beginWork(finishedWork);
}

commitRoot 函数首先会调用 beginWork 函数,该函数会执行以下三个步骤:

  1. finishedWork 作为根节点,开始遍历虚拟 DOM 树。
  2. 在遍历过程中,调用 commitUnmount 函数卸载所有需要卸载的组件。
  3. 在遍历过程中,调用 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 函数首先会遍历 finishedWorkfirstEffect 属性,然后调用 commitEffectUnmount 函数执行卸载副作用。

总结

在本文中,我们介绍了 React17 源码中 commit 阶段的实现原理和源码剖析。我们重点介绍了 commit 阶段中 commitRoot 函数的作用,包括它的执行过程和源码细节。同时,还介绍了 commitRoot 函数是如何处理副作用、更新 DOM 和协调新旧状态的。本文适合对 React 源码和更新过程感兴趣的开发者阅读。