React函数式组件渲染、useEffect顺序总结
参考资料:
深入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]
- 先执行unmount的组件的clean,执行顺序是先序DFS,即
- 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]
- 先执行unmount的组件的clean,执行顺序是先序DFS,即
- 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]
React函数式组件渲染、useEffect顺序总结的更多相关文章
- 如何对 React 函数式组件进行优化
文章首发个人博客 前言 目的 本文只介绍函数式组件特有的性能优化方式,类组件和函数式组件都有的不介绍,比如 key 的使用.另外本文不详细的介绍 API 的使用,后面也许会写,其实想用好 hooks ...
- React函数式组件和类组件[Dan]
一篇对Dan的 How Are Function Components Different from Classes? 一文的个人阅读总结,内容来自于此.强烈推荐阅读 Dan Abramov.的博客. ...
- React函数式组件使用Ref
目录: 简介 useRef forwardRef useImperativeHandle 回调Ref 简介 大家都知道React中的ref属性可以帮助我们获取子组件的实例或者Dom对象,进而对子组件进 ...
- React函数式组件的性能优化
优化思路 主要优化的方向有2个: 减少重新 render 的次数.因为在 React 里最重(花时间最长)的一块就是 reconction(简单的可以理解为 diff),如果不 render,就不会 ...
- React 函数式组件的 Ref 和子组件访问(useImperativeHandle)
引入:如何调用函数式组件内部的方法 对于 React 中需要强制修改子组件的情况,React 提供了 Refs 这种解决办法,使得我们可以操作底层 DOM 元素或者自定的 class 组件实例.除此之 ...
- React函数式组件值之useRef()和useImperativeHandle()
一.useRef useRef共有两种用法,获取子组件的实例(只有类组件可用),在函数组件中的一个全局变量,不会因为重复 render 重复申明, 类似于类组件的 this.xxx. 1. useRe ...
- react中类组件、函数组件、state、单层遍历、多层遍历、先遍历后渲染、if-else、三目运算符
1.回顾 module.exports = { entry: {}, output: {}, plugins: [], module: {}, resolve: {}, devServe: {} } ...
- 函数式组件中实现Antd打开Modal后其Input框自动聚焦(focus)到文字的最后
目前React使用函数式组件已经成为趋势, 如何把React函数式组件用好, 提高性能, 从而实现业务需求也成为了一种能力的体现......咳咳咳, 进入正题: 现实场景需求 我想实现这一个需求, 父 ...
- react 中的无状态函数式组件
无状态函数式组件,顾名思义,无状态,也就是你无法使用State,也无法使用组件的生命周期方法,这就决定了函数组件都是展示性组件,接收Props,渲染DOM,而不关注其他逻辑. 其实无状态函数式组件也是 ...
- 渲染函数render和函数式组件
vnode对象 vnode对象包括(vnode并不是vue实例,而是vue实例中渲染函数render执行后生成的结果) this.tag = tag // 当前节点标签名 this.data = da ...
随机推荐
- Python学习——Juptyer Notebook快捷键的使用
1. 运行当前Cell:Ctrl + Enter 2. 运行当前Cell并在其下方插入一个新的Cell:Alt + Enter 3. 运行当前Cell并选中其下方的Cell:Shift + Enter ...
- PaddleDetection 快速上手
PaddleDetection 快速上手 本项目以路标数据集roadsign为例,详细说明了如何使用PaddleDetection训练一个目标检测模型,并对模型进行评估和预测. 本项目提供voc格式的 ...
- 【解决方法】查找比较组时报错:An object (User, Group, or Built-in security principal) with the following nameca..
目录-快速跳转 问题描述 原因分析: 解决方案: 附言: 问题描述 操作环境与场景: 在 VM 内 Windows 2019 中,在组策略管理中,对GPO进行组查找时报错: An object (Us ...
- GE反射内存实时通讯网络解决方案
时通讯网络是用于需要较高实时性要求的应用领域的专用网络通讯技术,一般采用基于高速网络的共享存储器技术实现.它除了具有严格的传输确定性和可预测性外,还具有速度高.通信协议简单.宿主机负载轻.软硬件平台适 ...
- 5分钟实现调用ChatGPT接口API实现多轮问答
5分钟实现调用ChatGPT接口API完成多轮问答 最近ChatGPT也是火爆异常啊,在亲自使用了几个月之后,我发现这东西是真的好用,实实在在地提高了生产力.那么对于开发人员来说,有时候可能需要在自己 ...
- 学node 之前你要知道这些
初识nodejs 19年年底一个偶然的机会接到年会任务,有微信扫码登录.投票.弹幕等功能,于是决定用node 来写几个服务,结果也比较顺利. 当时用看了下koa2的官方文档,知道怎么连接数据库 ...
- 数据剖析更灵活、更快捷,火山引擎 DataLeap 动态探查全面升级
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 近期,火山引擎 DataLeap 上线"动态探查"能力,为用户提供全局数据视角.完善的抽样策略 ...
- 2021-07-21:一张扑克有3个属性,每种属性有3种值(A、B、C),比如“AAA“,第一个属性值A,第二个属性值A,第三个属性值A,比如“BCA“,第一个属性值B,第二个属性值C,第三个属性值A
2021-07-21:一张扑克有3个属性,每种属性有3种值(A.B.C),比如"AAA",第一个属性值A,第二个属性值A,第三个属性值A,比如"BCA",第一个 ...
- ChatGPT Plugin开发setup - Java(Spring Boot) Python(fastapi)
记录一下快速模板,整体很简单,如果不接auth,只需要以下: 提供一个/.well-known/ai-plugin.json接口,返回openAI所需要的格式 提供openAPI规范的文档 CORS设 ...
- python环境的安装与设置和oneforall的安装与使用
下载python: https://www.python.org/downloads/windows/ 安装python 如果不需要修改路径,下面两个√打开后,点击上面的install now 也可以 ...