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

news2024/12/24 2:21:11

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

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

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

它表示 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.coloradmin.cn/o/2231508.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java毕业设计之基于Bootstrap的常州地方旅游管理系统的设计与实现(springboot)

项目简介 基于Bootstrap的常州地方旅游管理系统的设计与实现有下功能&#xff1a; 基于Bootstrap的常州地方旅游管理系统的设计与实现的主要使用者分为用户功能模块和管理员功能模块两大部分&#xff0c;用户可查看景点信息、景点资讯等&#xff0c;注册登录后可进行景点订票…

单链表OJ题(3):合并两个有序链表、链表分割、链表的回文结构

目录 一、合并两个有序链表 二、链表分割 三、链表的回文结构 u解题的总体思路&#xff1a; 合并两个有序链表&#xff1a;首先创建新链表的头节点&#xff08;哨兵位&#xff1a;本质上是占位子&#xff09;&#xff0c;为了减少一些判断情况&#xff0c;简化操作。然后我们…

为数据集而生的 SQL 控制台

随着数据集的使用量急剧增加&#xff0c;Hugging Face 社区已经变成了众多数据集默认存放的仓库。每月&#xff0c;海量数据集被上传到社区&#xff0c;这些数据集亟需有效的查询、过滤和发现。 Dataset Monthly Creations 每个月在 Hugging Face Hub 创建的数据集 我们现在非常…

简易了解Pytorch中的@ 和 * 运算符(附Demo)

目录 1. 基本知识2. 3. * 1. 基本知识 在 PyTorch 中&#xff0c; 和 * 运算符用于不同类型的数学运算&#xff0c;具体是矩阵乘法和逐元素乘法 基本知识 运算符功能适用场景示例矩阵乘法&#xff08;或点乘&#xff09;用于执行线性代数中的矩阵乘法C A B&#xff0c;其中…

JavaScript知识点梳理及案例实践

1. Date对象 创建Date对象 //方法1&#xff1a;不指定参数 var nowd1new Date(); console.log(nowd1.toLocaleString( )); //方法2&#xff1a;参数为日期字符串 var d2new Date("2004/3/20 11:12"); console.log(d2.toLocaleString( )); var d3new Date("04/…

推荐一款Windows维护和修复工具包:RepairKit

RepairKit是一个综合性的Java开发的Windows修复和维护工具包。该工具包旨在为用户提供一个专用的系统修复工具&#xff0c;并快速访问一些操作系统功能及其他附带的电脑维护软件。 RepairKit 提供了一个简单有效的解决方案&#xff0c;用于维护PC的顺畅运行。它包括自动修复/清…

cocos开发QA

目录 TS相关foreach循环中使用return循环延迟动态获取类属性 Cocos相关属性检查器添加Enum属性实现不规则点击区域使用cc.RevoluteJoint的enable激活组件无效本地存储以及相关问题JSON.stringify(map)返回{}数据加密客户端复制文本使用客户端方法热更新LabelOutline.color is d…

大数据新视界 -- 大数据大厂之 Impala 性能优化:数据存储分区的艺术与实践(下)(2/30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

记第一次本地编译seatunnel源码

拉取代码 git clone https://github.com/apache/seatunnel.git 使用版本 我们生产环境用的是2.3.5版本&#xff0c;所以基于2.3.5-release分支代码进行编译。 maven package过程 遇到的第一个问题&#xff1a;‘com.sun.tools.javac.tree.JCTree com.sun.tools.javac.tree…

6.1、属性动画

使用显式动画产生布局更新动画 1.旋转动画 只修改对应的属性 rotate({angle: this.angle}) 即可达到效果 动画效果 对应实现代码 @Entry @Component struct AnimationPage {@State angle:number = 0aboutToAppear() {

串口屏控制的自动滑轨(未完工)

序言 疫情期间自己制作了一个自动滑轨&#xff0c;基于无线遥控的&#xff0c;但是整体太大了&#xff0c;非常不方便携带&#xff0c;所以重新设计了一个新的&#xff0c;以2020铝型材做导轨的滑轨&#xff0c;目前2020做滑轨已经很成熟了&#xff0c;配件也都非常便宜&#x…

Git在码云上的使用指南:从安装到推送远程仓库

目录 前言&#xff1a; 1、git的安装 1.1.Linux-centos环境下安装 1.2.Linux-ubuntu环境下安装 2.创建Git本地仓库 3.配置Git 4.认识⼯作区、暂存区、版本库 5.添加文件 5.1.git命令 5.2.commit命令 6.远程操作 6.1.新建远程仓库 6.2.克隆远程仓库&#xff1a; 6…

GESP4级考试语法知识(冒泡排序)

冒泡排序参考程序&#xff1a; #include <iostream> using namespace std; const int MAXN10001; int main() {int n,i,j;float a[MAXN];cin>>n;for(i1;i<n;i)cin>>a[i]; //输入n个数bool ok;for(in;i>1;i--){oktrue; //判断是…

无人机场景 - 目标检测数据集 - 夜间车辆检测数据集下载「包含VOC、COCO、YOLO三种格式」

数据集介绍&#xff1a;无人机场景夜间车辆检测数据集&#xff0c;真实场景高质量图片数据&#xff0c;涉及场景丰富&#xff0c;比如夜间无人机场景城市道路行驶车辆图片、夜间无人机场景城市道边停车车辆图片、夜间无人机场景停车场车辆图片、夜间无人机场景小区车辆图片、夜…

重学SpringBoot3-整合 Elasticsearch 8.x (一)客户端方式

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 这里写目录标题 1. 为什么选择 Elasticsearch&#xff1f;2. Spring Boot 3 和 Elasticsearch 8.x 的集成概述2.1 准备工作2.2 添加依赖 3. Elasticsearch 客户端配置方式…

动态规划应该如何学习?

动态规划如何学习 参考灵神的视频和题解做的笔记&#xff08;灵神YYDS&#xff0c;以后也都会用这套逻辑去思考&#xff09; 枚举选哪个&#xff1a; 动态规划入门&#xff1a;从记忆化搜索到递推_哔哩哔哩_bilibili 746. 使用最小花费爬楼梯 - 力扣&#xff08;LeetCode&a…

从零开始构建 ChatGPT

今天&#xff0c;我们要介绍的是一个名为 LLMs-from-scratch 的 GitHub 项目&#xff0c;它由开发者 rasbt 精心打造&#xff0c;旨在一步步教你如何使用 PyTorch 从零开始实现一个类似 ChatGPT 的大型语言模型&#xff08;LLM&#xff09;。 这是一个教育性质的开源项目&…

音视频听译:助力多维度沟通与发展的大门

在全球经济一体化的大背景下&#xff0c;企业之间的跨国合作愈发频繁。在商务会议、谈判和产品演示等活动中&#xff0c;语言的多样性成为了一大挑战。而音视频听译服务能够将不同语言的音频准确转换为目标语言文字&#xff0c;确保信息的精准传达&#xff0c;避免因语言障碍引…

向量模型Jina Embedding: 从v1到v3论文笔记

文章目录 Jina Embedding: 从v1到v3Jina Embedding v1数据集准备训练过程 Jina Embedding v2预训练修改版BERT在文本对上微调在Hard Negatives上微调 Jina Embedding v2 双语言预训练修改版BERT在文本对上微调用多任务目标微调 Jina Embedding v3预训练在文本对上微调训练任务相…

为啥学习数据结构和算法

基础知识就像是一座大楼的地基&#xff0c;它决定了我们的技术高度。而要想快速做出点事情&#xff0c;前提条件一定是基础能力过硬&#xff0c;“内功”要到位。 想要通关大厂面试&#xff0c;千万别让数据结构和算法拖了后腿 我们学任何知识都是为了“用”的&#xff0c;是为…