React函数式组件渲染、useEffect顺序总结

2023-11-19

参考资料:
深入React的生命周期(上):出生阶段(Mount)
深入React的生命周期(下):更新(Update)
精读《useEffect 完全指南》
React组件重新渲染理解 & 优化大全
React渲染顺序及useEffect执行顺序探究(含并发模式)

组件状态

同样还是可以把组件的状态分为mount、update和unmount。

  • mount:组件首次出现在页面中。React会通过最后组件的函数返回值,确定它有哪些子组件,依次mount和render子组件。一个component只是定义了,但没有最后被返回,就不会被挂载和渲染。
  • update:组件的重新渲染,重新渲染的条件见这里
  • unmount:如果组件从页面消失,就会被unmount。常见于条件渲染、或者子组件未使用key标明时的位置更改。

React16的组件渲染过程

即使用ReactDOM.createRoot(DOM).render(<App />)渲染组件时。

单一组件渲染过程

在组件的不同阶段,调用顺序如下

mount

  • 函数体:此时useState等hooks取初始值,如果用callback初始化,则会调用初始化函数
  • effect函数:会调用一遍所有useEffect注册的函数,调用顺序就是useEffect在函数体里出现的顺序

update

  • 函数体:正常调用,取最新state和ref的值

  • clean函数:如果依赖项A=[…]发生改变,则会调用,但若有其它依赖项B也变了,却没列进依赖项里,这些未注册依赖项会使用最后一次A=[…]发生改变时的B的值。因为这是clean函数最新的定义。

    样例可见React函数式组件渲染顺序探究(Demo),组件依赖了name和state,但只注册了state这一个依赖项。

  • effect函数:如果依赖项A=[…]发生改变,则会调用,但若有其它依赖项B也变了,却没列进依赖项里,这些未注册依赖项会使用最后一次A=[…]发生改变时的B的值。因为这是effect函数最新的定义。

unmount

  • clean函数:会调用一遍所有useEffect返回的clean函数,调用顺序也是注册顺序。同样,也取的是它最新的定义。

    假设有两个effect,都有未注册依赖项B。但它们一个依赖项为A=[…],另一个为[]

    如果最开始B=1,而A变的时候B=2,最后unmount的时候,前者的B=2,后者的B=1,因为后者的clean函数并未更新。

树型组件调用顺序

mount

如果有一个这样的component:

<A>
    <A1>
        <A1_1/>
        <A1_2/>
    </A1>
    <A2>
        <A2_1/>
        <A2_2/>
    </A2>
</A>
  • 函数体:调用顺序是先序遍历的DFS,即[A, A1, A1_1, A1_2, A2, A2_1, A2_2]
  • effect:类似于二叉树的后序遍历,先遍历孩子,再遍历根,即:[A1_1, A1_2, A1, A2_1, A2_2, A2, A]

update

如果上述的component变成了如下,A重新渲染。

<A>
    <A2>
        <A2_1/>
        <A2_2/>
    </A2>
    <A1>
        <A1_1/>
        <A1_2/>
    </A1>
</A>
  • 如果A1和A2没有设置key,React会当作需要unmount旧的A1、A2,再mount新的A1、A2。
  • 否则,React只会重新渲染A1、A2。

假设这里A1设置了key,而A2没有:

  • 函数体:按当前组件内容的先序DFS:[A1, A1_1, A1_2, A2, A2_1, A2_2]
  • clean:
    • 先执行unmount的组件的clean,执行顺序是先序DFS,即[A2, A2_1, A2_2]
    • 再执行update组件的clean,执行顺序是后序DFS,即[A1_1, A1_2, A1]
  • effect:按当前组件内容的后序DFS执行,即[A2_1, A2_2, A2, A1_1, A1_2, A1]

React18的更新

即使用StrictMode渲染组件时。

root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

与16最大的区别是:

(1)函数体都会被调用2遍

(2)新mount的组件都会再次调用一遍clean和effect

有点类似于, mount (React 18)约等于mount(React 16) + update(React 16)

所以:

  • 第一次body即mount的body,第二次body是update的body

    但也不完全相同,比如,如果使用callback来初始化state的值时,mount的时候调用的两遍函数体,都是会调用这个callback的,而不是一次调用一次不调用。

  • 第一次effect是mount的effect

  • 接下来的clean和effect是update时的clean+effect

mount

如果有一个这样的component:

<A>
    <A1>
        <A1_1/>
        <A1_2/>
    </A1>
    <A2>
        <A2_1/>
        <A2_2/>
    </A2>
</A>
  • 函数体:调用顺序是先序遍历的DFS,即[A, A1, A1_1, A1_2, A2, A2_1, A2_2]。由于会叫两遍,实际上是[A, A, A1, A1, A1_1, A1_1, A1_2, A1_2, A2, A2, A2_1, A2_1, A2_2, A2_2]
    • 有意思的是,不是先mount DFS一遍,update DFS一遍,是在DFS的过程中直接叫两遍函数体。
  • effect:类似于二叉树的后序遍历,先遍历孩子,再遍历根,即:[A1_1, A1_2, A1, A2_1, A2_2, A2, A]
  • clean:后序DFS[A1_1, A1_2, A1, A2_1, A2_2, A2, A]
  • effect:后序DFS[A1_1, A1_2, A1, A2_1, A2_2, A2, A]

update

如果上述的component变成了如下,A重新渲染。

<A>
    <A2>
        <A2_1/>
        <A2_2/>
    </A2>
    <A1>
        <A1_1/>
        <A1_2/>
    </A1>
</A>
  • 如果A1和A2没有设置key,React会当作需要unmount旧的A1、A2,再mount新的A1、A2。
  • 否则,React只会重新渲染A1、A2。

假设这里A1设置了key,而A2没有:

  • 函数体:按当前组件内容的先序DFS:[A1, A1_1, A1_2, A2, A2_1, A2_2]。同样会调用2次。
  • clean:
    • 先执行unmount的组件的clean,执行顺序是先序DFS,即[A2, A2_1, A2_2]
    • 再执行update组件的clean,执行顺序是后序DFS,即[A1_1, A1_2, A1]
  • effect:按当前组件内容的后序DFS执行,即[A2_1, A2_2, A2, A1_1, A1_2, A1]
  • clean:mount的组件会被update,所以会有第二轮clean,后序DFS,即[A2_1, A2_2, A2]
  • effect:第二轮effect,即[A2_1, A2_2, A2]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React函数式组件渲染、useEffect顺序总结 的相关文章

  • 需要使用 iFrame API 隐藏 YouTube 品牌

    我正在使用 YouTube iFrame API 在我的自定义播放器 javascript 播放器 中加载视频 我需要隐藏 Youtube 品牌 但是在 iOS 设备上 它显示带有以下参数的徽标 playerVars fs 1 autopl
  • Bootstrap 标签栏平滑移动导航按钮

    我有一个用于切换块的普通引导选项卡面板 在导航中切换块时 活动选项卡会突出显示 但现在 当我单击活动选项卡的背景时 它会立即发生变化 是否可以使切换选项卡时背景不会立即改变 而是根据需要哪个选项卡而平滑地左右移动 这可以用以下方法完成吗cs
  • 在 JavaScript 函数中加载图像

    我有获取图像像素颜色的功能 function getImage imgsrc var img img src imgsrc var imageMap new Object img load function var canvas
  • jQuery UI Datepicker 奇怪的行为

    我在使用 jqueryUI 使用简单的日期选择器时遇到了一个奇怪的问题 我只想显示两个月的日历 包括上个月和当前月份 我使用了这段代码 function picker datepicker numberOfMonths 2 showCurr
  • 在 React 中使用 .less 文件

    我正在尝试将 less 文件与极简主义 React 应用程序一起使用 使用创建反应应用程序 我已经添加less and less loader to my 包 json以及我的模块规则webpack config js文件 然而 类引用并未
  • 如何按 Angular 表中的属性(该属性具有单个 rownspan)进行分组?

    我没有找到这个问题的合适标题 我的问题是 例如 我有一个包含两列的表 列汽车品牌和列汽车型号 我希望表是 like in this picture 换句话说 品牌名称只会出现 1 次 我的输入数组采用以下 json 格式 brand Aud
  • D3 向对象添加超链接?

    我正在尝试制作 D3 图 它将代表我网站的菜单 我尝试按照此处的其他指南添加超链接 但它们都不起作用 每个对象都会有一个不同的 URL 指向 主页 关于 联系方式等 如果添加超链接 我可以拖动对象吗 这意味着如果我按住单击 如果我单击该对象
  • 如何在新窗口中打开图像或pdf文件?

    我有一个 gridview 它包含文件名和文件路径 图像和 pdf 格式文件 其中我使用了模板字段 在该字段下放置了 1 个图像按钮 单击该图像按钮 即 查看 按钮 时 我想在新窗口中打开所选文件 这是我的代码 protected void
  • AngularStrap 工具提示禁用我的自定义指令

    我正在尝试让 bs tooltip AngularStrap 指令与我自己的名为 checkStrength 的自定义指令一起使用 该指令检查密码的强度 单独使用这些指令中的任何一个时 它们都可以正常工作 但不能一起工作 This http
  • 使 Bootstrap Popover 在悬停而不是单击时出现/消失

    我正在使用 Bootstrap 构建一个网站Popover http twitter github com bootstrap javascript html popovers我不知道如何使弹出窗口出现在悬停而不是单击时 我想做的就是当有人
  • 在 Android Chrome 中隐藏 HTML5 音频/视频通知

    我的网络应用程序上有一个 HTML5 音频元素 在某些时候 我使用以下代码以编程方式停止播放 audioElement pause audioElement currentTime 0 播放音频时 我的 Android 设备 使用 Goog
  • for循环中需要声明变量吗?

    有什么区别 for var i 0 i lt 5 i for i 0 i lt 5 i 是否有必要包含 var 关键字 我知道 var 关键字会影响变量范围 但我无法理解是否有必要在 for 循环中包含该关键字 在第二个示例中 您的变量是全
  • 在 Nodejs 中,如何停止 FOR 循环直到 MongoDB 调用返回

    我正在研究下面的代码片段 我有一个名为 stuObjList 的 JSON 对象数组 我想循环遍历数组以查找具有特定标志集的特定 JSON 对象 然后进行数据库调用以检索更多数据 当然 FOR 循环不会等待数据库调用返回并到达 j leng
  • 使用 ng-if 改变角度方向

    我想通过单击将方向从 rtl 更改为 ltr and in 设置 html
  • 在这个反应示例中,bind 做了什么?

    什么是bind在这个声明中做this tick bind 这个 在下面的代码中 export class Counter extends React Component constructor props super props this
  • 在 React Web 应用程序中使用 createjs-soundjs

    我想用https www npmjs com package createjs soundjs https www npmjs com package createjs soundjs在 React Web 应用程序上播放声音 我正常安装了
  • 标记(Markdown)+ Mermaid(流程图和图表)

    努力去争取 美人鱼 https github com knsv mermaid https github com knsv mermaid跟 共事 标记 https github com chjj marked https github c
  • 使用 File API polyfill 读取数据 URL

    我正在尝试使用文件 API 库 https github com mailru FileAPI https github com mailru FileAPI 作为不支持文件 API 的浏览器的后备 以便将文件作为数据 URL 读取并将其传
  • Chrome 调试器注入 javascript

    我有这样的好奇心 是否可以以某种方式在我的页面中注入 javascript 并执行它并调试它 正如您在控制台中所做的那样 但在控制台中您无法暂停并观察变量 是否可以调试我通过控制台输入的代码 为什么无法调试通过 XHR 接收的代码 Than
  • Jquery 以编程方式更改

    文本

    编辑 解决方案是将其添加到个人资料页面而不是性别页面 profile live pageinit function event p pTest text localStorage getItem gender 我在列表视图中有一个带有一些文

随机推荐

  • 计算机c盘拒绝访问怎么办,怎么解决Win7系统C盘文件拒绝访问

    一位重装系统用户在Win7系统环境下翻开文件 文件夹或者C盘 提示 回绝访问 这是通常由于你的权限不够 假如想要继续访问这些位置就要取代更高的权限 下面就来详细引见一下Win7系统C盘文件回绝访问的处理办法 一 Win7 C盘回绝访问的缘由
  • 【python教程入门学习】Python爬虫入门学习:网络爬虫是什么

    网络爬虫又称网络蜘蛛 网络机器人 它是一种按照一定的规则自动浏览 检索网页信息的程序或者脚本 网络爬虫能够自动请求网页 并将所需要的数据抓取下来 通过对抓取的数据进行处理 从而提取出有价值的信息 认识爬虫 我们所熟悉的一系列搜索引擎都是大型
  • C++模板的使用

    参考博客 https www cnblogs com sevenyuan p 3154346 html 以下内容是摘抄以上博主的博客 1 定义 模板定义 模板就是实现代码重用机制的一种工具 它可以实现类型参数化 即把类型定义为参数 从而实现
  • websphere没有显示服务器,webserver不显示的问题

    运行configurewebserver1 sh时的信息 root iasd10g bin configurewebserver1 sh WASX7209I x 4F7F x 7528 SOAP x 8FDE x 63A5 x 5668 x
  • Python中的any()和all()

    any any 函数采用iterable作为参数 any iterable 迭代器可以是列表 元组或字典 如果iterable中的所有元素为true 则any 函数将返回 True 但是 如果传递给该函数的Iterable为空 则返回 Fa
  • Discord教程:Discord账号注册、Discord多账号登录和管理

    Discord最初是为游戏玩家在群聊和交流而创建的 但自疫情爆发以来 许多企业 公司和初创公司发现 居家办公时使用Discord进行日常沟通非常便捷 Discord不再是仅限于游戏玩家 平台建立了不同于其他任何社交空间的新空间 封闭又开放的
  • 史上最全的《Android面试题及解析》,赶紧收藏!

    写在文章前面的话 工欲行其事 必先利其器 英雄和侠客更需要宝剑助己成功 同样 在现代软件开发环境中 每个Android开发者都需要更好的工具 帮助我们增强功能 提高效率 在这个竞争激烈的行业中 只有优秀的工程师能够生存 需要我们能够为客户提
  • C++-map和set

    本期我们来学习map和set 目录 关联式容器 键值对 pair 树形结构的关联式容器 set multiset map multimap 关联式容器 我们已经接触过 STL 中的部分容器 比如 vector list deque forw
  • layui 勾选不联动父项 树形控件_layui实现checkbox的目录树tree的例子

    废话不多说啦 我就直接上代码吧 需要的朋友可以过来参考下 layui use tree function layui jquery form layui form 获取节点数据 getTreeData function getTreeDat
  • 【华为OD】

    目录 一 题目描述 二 输入描述 三 输出描述 示例一 输入 输出 说明 示例二 输入 输出 说明 四 Java玩法 一 题目描述 现有两个整数数组 需要你找出两个数组中同时出现的整数 并按照如下要求输出 1 有同时出现的整数时 先按照同时
  • stable diffusion基础

    整合包下载 秋叶大佬 AI绘画 8月最新 Stable Diffusion整合包v4 2发布 参照 基础04 目前全网最贴心的Lora基础知识教程 VAE 作用 滤镜 微调 VAE下载地址 C站 https civitai com mode
  • gcc源码编译中的问题处理过程

    1 需求是想要gcc可以编译32位程序也可以编译64位程序 机器是64位的 编译过程教程参考 https www quyu net info 782 html 但是configure配置时不能配置 disable multilib 如果配置
  • Java代码生成器Easy Code

    EasyCode是基于IntelliJ IDEA开发的代码生成插件 支持自定义任意模板 Java html js xml 只要是与数据库相关的代码都可以通过自定义模板来生成 支持数据库类型与java类型映射关系配置 支持同时生成生成多张表的
  • Python3 configparse模块(配置)

    Python3 configparse模块 配置 参考 https www cnblogs com bert227 p 9326313 html https www cnblogs com dion 90 p 7978081 html py
  • Mac下建立渗透测试环境:代理工具篇

    SSH完整命令行参数 D 绑定一个地址和端口 p 指定ssh连接的端口 L bind address port host hostport 指定本地端口和远程服务器的端口 将本地端口上的数据 发送到指定的远程端口上 R bind addre
  • ClickHouse进阶(十六):clickhouse优化-表优化

    进入正文前 感谢宝子们订阅专题 点赞 评论 收藏 关注IT贫道 获取高质量博客内容 个人主页 含各种IT体系技术 IT贫道 大数据OLAP体系技术栈 Apache Doris Kerberos安全认证 CSDN博客 订阅 拥抱独家专题 你的
  • linux 查看git,maven, java,haproxy,mysql,python,ansible等等版本命令汇总

    git版本 tom test git version git version 1 8 3 1 maven 版本 tom test mvn v Apache Maven 3 6 1 d66c9c0b3152b2e69ee9bac180bb8f
  • [BJOI2014]大融合【LCT维护子树信息】

    题目链接 本题保证不会构成环 此为前提 然后操作是查询 或者接上一条边 保证之前两点不连通 好了 接下去就是正经事儿了 在此之前 已经有了利用LCT来维护树链信息了 现在只要在这基础上稍加改变 就可以维护某点 也可以是不定根 的子树信息了
  • nginx:实时流量拷贝mirror模块

    ngx http mirror module模块 实时流量拷贝 precontent阶段的mirror模块 默认编译进nginx模块 通过 without ngx http mirror module禁用模块 功能 创造一份镜像流量 生产环
  • React函数式组件渲染、useEffect顺序总结

    参考资料 深入React的生命周期 上 出生阶段 Mount 深入React的生命周期 下 更新 Update 精读 useEffect 完全指南 React组件重新渲染理解 优化大全React渲染顺序及useEffect执行顺序探究 含并