[FE] React 初窥门径(四):React 组件的加载过程(render 阶段)

news/2024/12/5 18:45:51/

1. 回顾

前几篇文章中,我们采用了 VSCode 插件 CodeTour 来记录代码的执行过程,
并把相关的数据 .tour/ 放到了 github: thzt/react-tour 中。

截止到本文为之,我们总共记录了这些 code-tour,

.tour/
├── 2. 构建过程.tour
├── 3.1 react 的加载过程.tour
├── 3.2 react-dom 的加载过程.tour
├── 4.1 组件加载过程:函数组件(call stack).tour
├── 4.1.1 组件加载过程:函数组件(全流程).tour
└── 4.2 组件加载过程:类组件(call stack).tour

本文重点介绍 4.1.1 组件加载过程:函数组件(全流程) 相关的内容。

2. 极简的示例项目

现在我们开始介绍 React 函数组件的加载全流程,我们的示例项目如下,
github: thzt/react-tour/example-project

example-project/
├── README.md
├── package.json
├── public
|  └── index.html
├── src
|  ├── App.js
|  └── index.js
└── yarn.lock

其中,index.js 的内容如下,

import React from 'react';
import ReactDOM from 'react-dom';import App from './App';ReactDOM.render(<App />,document.getElementById('root')
);

App.js 的内容如下,

const App = () => {debugger;return 'hello world'
};export default App;

当前 React 项目只加载了一个 <App /> 组件,这个组件只返回了一段纯文本 'hello world'

与 React 初窥门径(一):环境准备 介绍的一致,我们可以启动项目,

$ yarn
$ yarn start# http://127.0.0.1:3000

3. 调试 Web 项目

参考 React 初窥门径(三):用 VSCode 调试,
我们将 github: thzt/react-tour 中的文件,拷贝到 React 源码根目录,

  • package.json:直接覆盖,其中新增了 debug-build 这个 npm scripts
  • .vscode/:拷贝到 React 源码目录,其中包含了两个 debug 配置,我们要用 Debug React 这个配置
  • .tour/:VSCode CodeTour 插件的数据

整体操作流程如下:
(1)示例项目操作过程

  • 下载 github: thzt/react-tour/example-project 示例项目
  • 给示例项目安装依赖:yarn
  • 替换 example-projectnode_modules 中的依赖 reactreact-dom
    参考 React 初窥门径(一):环境准备
    可使用工具 github: thzt/react-tour/tool/link.bash
  • 启动示例项目:yarn starthttp://127.0.0.1:3000

(2)React 源码操作过程

  • 下载(克隆) React 源码,并切换到 v17.0.2
  • 拷贝 github: thzt/react-tour 中的 package.json .vscode/ .tour/ 到 React 源码目录
  • 选择 Debug React 选项进行调试

我们发现 VSCode 的断点停在了 example-project/src/App.js 文件中。

const App = () => {debugger;              // <- 断点到了这里return 'hello world'
};export default App;

4. 调用栈

我们先来跟踪一下,从 ReactDOM.render 到 App 组件 debugger 位置的调用栈,

在 CodeTour(.tour/)中,也记录了这个过程,

4.1 组件加载过程:函数组件(call stack)

render
legacyRenderSubtreeIntoContainer
unbatchedUpdates
fn
updateContainer
scheduleUpdateOnFiber
performSyncWorkOnRoot
renderRootSync
workLoopSync
performUnitOfWork
beginWork$1
beginWork
mountIndeterminateComponent
renderWithHooks

以上调用栈只展示了函数的链式调用关系,如果用缩进表示调用链路的话,它应该是这样的,

renderlegacyRenderSubtreeIntoContainerunbatchedUpdatesfnupdateContainerscheduleUpdateOnFiberperformSyncWorkOnRootrenderRootSyncworkLoopSyncperformUnitOfWorkbeginWork$1beginWorkmountIndeterminateComponentrenderWithHooks

它表示 render 调用了 legacyRenderSubtreeIntoContainer
legacyRenderSubtreeIntoContainer 又调用了 unbatchedUpdates
unbatchedUpdates 又调用了 fn 等等,直到最后调用了 renderWithHooks

最后 renderWithHooks 调用了函数组件 App,来到断点那里。

5. 全流程

只看调用栈的话,React 组件的加载过程还不完整,我们知道某个函数之前别调用之前,是否还调用了其他函数,
以下我们整理了从 renderApp 调用的全流程(函数前面的数字,表示缩进层次)。

4.1.1 组件加载过程:函数组件(全流程)
(下图包含代码折叠,而且只截了一部分,完整版请查看上面的链接)

6. render 和 commit 阶段

全流程包含了特别多的细碎逻辑,我们首先想弄明白的是,

  • 组件是何时被调用的,组件返回之后发生了什么(render 阶段)
  • 组件是如何展示在页面上的(commit 阶段)

这两个阶段,就是 performSyncWorkOnRoot 做的事情了,在大图中它处于这个位置,

可以看到:

  • render 阶段(renderRootSync:根据用户创建的 React 组件,创建 Fiber Tree(先从上到下 performUnitOfWork ,再从下到上 completeWork
  • commit 阶段(commitRoot:把 Fiber Tree 实际写入到 DOM 中

一图胜千言,(函数前面的数字,表示缩进层次)

[6] performSyncWorkOnRoot[7] renderRootSync[8] markRenderStarted                                         <- render 阶段开始[8] workLoopSync[9] performUnitOfWork ---- [HostRoot {tag: 3}]              <- 从 根元素 开始向下构建 Fiber Tree[10] beginWork$1[11] beginWork[12] updateHostRoot                                   <- 加载 根元素 HostRoot[13] reconcileChildren[14] reconcileChildFibers                         <- 创建 child 子元素[15] reconcileSingleElement[16] createFiberFromElement[17] createFiberFromTypeAndProps[18] createFiber[9] performUnitOfWork ---- [IndeterminateComponent {tag: 2}] (<App />)[10] beginWork$1[11] beginWork[12] mountIndeterminateComponent                      <- 加载 函数组件 App[13] renderWithHooks[14] Component[13] reconcileChildren[14] mountChildFibers=reconcileChildFibers        <- 创建 child 子元素[15] reconcileSingleTextNode[16] deleteRemainingChildren[16] createFiberFromText[17] createFiber[9] performUnitOfWork ---- [HostText {tag: 6}] ('hello world')[10] beginWork$1[11] beginWork[12] updateHostText                                   <- 加载 纯文本 'hello world'[10] completeUnitOfWork                                   <- 开始倒着从 子节点 向上到 根节点 进行梳理[11] completeWork ---- [HostText {tag: 6}] ('hello world')[12] createTextInstance[13] createTextNode[14] createTextNode [HTMLElement] ('hello world') <- 实际创建 HTML[11] completeWork ---- [IndeterminateComponent {tag: 2}] (<App />)[11] completeWork ---- [HostRoot {tag: 3}][8] markRenderStopped                                         <- render 阶段结束[7] commitRoot                                                  <- commit 阶段开始

下文我们再仔细介绍 commit 阶段。


参考

github: facebook/react v17.0.2
VSCode: CodeTour
github: thzt/react-tour
github: thzt/react-tour/example-project
React 初窥门径(一):环境准备
React 初窥门径(三):用 VSCode 调试
4.1 组件加载过程:函数组件(call stack)
4.1.1 组件加载过程:函数组件(全流程)

最后编辑于:2024-10-27 15:38:40


喜欢的朋友记得点赞、收藏、关注哦!!!


http://www.ppmy.cn/news/1544417.html

相关文章

HTML入门教程22:HTML文件路径

一、绝对路径 定义&#xff1a;绝对路径是从网站根目录开始的完整路径&#xff0c;它包含了协议、域名和文件路径。例如&#xff0c;<script src"https://www.example.com/js/script.js"></script>就使用了绝对路径来引用外部的JavaScript文件。特点&am…

Gitlab-runner running on Kubernetes - hostAliases

*Config like this. *That in your helm values.yaml.

Redis设计与实现 学习笔记 第十四章 服务器

Redis服务器负责与多个客户端建立网络连接&#xff0c;处理客户端发送的命令请求&#xff0c;在数据库中保存客户端执行命令所产生的数据&#xff0c;并通过资源管理来维持服务器自身的运转。 14.1 命令请求的执行过程 如果我们使用客户端执行以下命令&#xff1a; 那么从客…

为Meta Spark准备3D模型

有许多工具可以帮助你为 Meta Spark Studio 创建 3D 对象&#xff0c;包括 Cinema4D、Blender 和 3ds Max。你还可以使用 Meta Spark Toolkit 优化 Blender 对象。 在本指南中&#xff0c;我们将介绍正确的设置&#xff0c;以便你可以成功地为 Meta Spark Studio 准备对象&…

b站小土堆PyTorch视频学习笔记(CIFAR10数据集分类实例)

1、准备数据集并查看数据集长度 train_data torchvision.datasets.CIFAR10(root"./data", trainTrue, transformtorchvision.transforms.ToTensor(), downloadTrue) test_data torchvision.datasets.CIFAR10(root"./data", trainFalse, transformtorch…

java项目之微服务在线教育系统设计与实现(springcloud)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的闲一品交易平台。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 微服务在线教育系统设计与…

7thonline第七在线7大价值助力品牌实现智能化商品管理

在高波动和不确定的商业环境中&#xff0c;精准的销售预测对于零售品牌灵活应对市场需求、降低决策风险至关重要。

使用 MMDetection 实现 Pascal VOC 数据集的目标检测项目练习(四) annaconda和pytorch

anaconda 一、下载 Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 在清华镜像网页选择版本&#xff0c;这里选的是&#xff1a; 下载得到文件&#xff1a;Anaconda3-2022.10-Linux-x86_64.sh。将文件拷贝到ubuntu的Downloads文件夹。…