参考资料:

深入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]

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

  1. 如何对 React 函数式组件进行优化

    文章首发个人博客 前言 目的 本文只介绍函数式组件特有的性能优化方式,类组件和函数式组件都有的不介绍,比如 key 的使用.另外本文不详细的介绍 API 的使用,后面也许会写,其实想用好 hooks ...

  2. React函数式组件和类组件[Dan]

    一篇对Dan的 How Are Function Components Different from Classes? 一文的个人阅读总结,内容来自于此.强烈推荐阅读 Dan Abramov.的博客. ...

  3. React函数式组件使用Ref

    目录: 简介 useRef forwardRef useImperativeHandle 回调Ref 简介 大家都知道React中的ref属性可以帮助我们获取子组件的实例或者Dom对象,进而对子组件进 ...

  4. React函数式组件的性能优化

    优化思路 主要优化的方向有2个: 减少重新 render 的次数.因为在 React 里最重(花时间最长)的一块就是 reconction(简单的可以理解为 diff),如果不 render,就不会 ...

  5. React 函数式组件的 Ref 和子组件访问(useImperativeHandle)

    引入:如何调用函数式组件内部的方法 对于 React 中需要强制修改子组件的情况,React 提供了 Refs 这种解决办法,使得我们可以操作底层 DOM 元素或者自定的 class 组件实例.除此之 ...

  6. React函数式组件值之useRef()和useImperativeHandle()

    一.useRef useRef共有两种用法,获取子组件的实例(只有类组件可用),在函数组件中的一个全局变量,不会因为重复 render 重复申明, 类似于类组件的 this.xxx. 1. useRe ...

  7. react中类组件、函数组件、state、单层遍历、多层遍历、先遍历后渲染、if-else、三目运算符

    1.回顾 module.exports = { entry: {}, output: {}, plugins: [], module: {}, resolve: {}, devServe: {} } ...

  8. 函数式组件中实现Antd打开Modal后其Input框自动聚焦(focus)到文字的最后

    目前React使用函数式组件已经成为趋势, 如何把React函数式组件用好, 提高性能, 从而实现业务需求也成为了一种能力的体现......咳咳咳, 进入正题: 现实场景需求 我想实现这一个需求, 父 ...

  9. react 中的无状态函数式组件

    无状态函数式组件,顾名思义,无状态,也就是你无法使用State,也无法使用组件的生命周期方法,这就决定了函数组件都是展示性组件,接收Props,渲染DOM,而不关注其他逻辑. 其实无状态函数式组件也是 ...

  10. 渲染函数render和函数式组件

    vnode对象 vnode对象包括(vnode并不是vue实例,而是vue实例中渲染函数render执行后生成的结果) this.tag = tag // 当前节点标签名 this.data = da ...

随机推荐

  1. ElementPlus 组件全局配置

    友链:语雀,在线文档协同平台 官方提供的全局配置:Config Provider 本文只做简单的模板参考,具体的配置请根据自己的业务灵活设置,如果你使用的是其它的ui框架,原理应该都差不多 入口文件的 ...

  2. SpringBoot导出Word文档的三种方式

    SpringBoot导出Word文档的三种方式 一.导出方案 1.直接在Java代码里创建Word文档,设置格式样式等,然后导出.(略) 需要的见:https://blog.csdn.net/qq_4 ...

  3. 数据治理之关键环节元数据管理开源项目datahub探索

    @ 目录 概述 定义 核心功能 概念 元数据应用 其他开源 架构 概览 组件 元数据摄取架构 服务体系结构 本地部署 环境要求 安装 摄取样例 摄取入门 介绍 核心概念 命令行MySQL摄取示例 配置 ...

  4. 2022-11-12:以下rust语言代码中,结构体S实现了crate::T1::T2的方法,如何获取方法列表?以下代码应该返回[“m1“,“m2“,“m5“],顺序不限。m3是S的方法,但并不属于c

    2022-11-12:以下rust语言代码中,结构体S实现了crate::T1::T2的方法,如何获取方法列表?以下代码应该返回["m1","m2"," ...

  5. 2022-08-11:以下go语言代码输出什么?A:panic;B:编译错误;C:json marshal 报错;D:null;E:nil。 package main import ( “e

    2022-08-11:以下go语言代码输出什么?A:panic:B:编译错误:C:json marshal 报错:D:null:E:nil. package main import ( "e ...

  6. 2022-05-28:某公司计划推出一批投资项目。 product[i] = price 表示第 i 个理财项目的投资金额 price 。 客户在按需投资时,需要遵循以下规则: 客户在首次对项目 pr

    2022-05-28:某公司计划推出一批投资项目. product[i] = price 表示第 i 个理财项目的投资金额 price . 客户在按需投资时,需要遵循以下规则: 客户在首次对项目 pr ...

  7. 2022-03-26:给定一个无向图, 从任何一个点x出发,比如有一条路径: x -> a -> b -> c -> y, 这条路径上有5个点并且5个点都不一样的话,我们说(x,a,b,c,y)是一条

    2022-03-26:给定一个无向图, 从任何一个点x出发,比如有一条路径: x -> a -> b -> c -> y, 这条路径上有5个点并且5个点都不一样的话,我们说(x ...

  8. 2021-12-02:给定一个字符串str,和一个正数k。 返回长度为k的所有子序列中,字典序最大的子序列。 来自腾讯。

    2021-12-02:给定一个字符串str,和一个正数k. 返回长度为k的所有子序列中,字典序最大的子序列. 来自腾讯. 答案2021-12-02: 单调栈.先进来的元素大,后进来的元素小. 时间复杂 ...

  9. <form>表单中的action和method使用方法

    <form action="" method="post"> form是表单   里面的内容是要提交出去的. action 是链接   点击浏览选择 ...

  10. 什么是 Spring?为什么学它?

    前言 欢迎来到本篇文章!在这里,我将带领大家快速学习 Spring 的基本概念,并解答两个关键问题:什么是 Spring,以及为什么学习 Spring. 废话少说,下面,我们开始吧! Spring 官 ...