当前位置: 首页 > news >正文

React的useLayoutEffect和useEffect执行时机有什么不同

我们先看下 React 官方文档对这两个 hook 的介绍,建立个整体认识

useEffect(create, deps):

该 Hook 接收一个包含命令式、且可能有副作用代码的函数。在函数组件主体内(这里指在 React 渲染阶段)改变 DOM、添加订阅、设置定时器、记录日志以及执行其他包含副作用的操作都是不被允许的,因为这可能会产生莫名其妙的 bug 并破坏 UI 的一致性。使用 useEffect 完成副作用操作。赋值给 useEffect 的函数会在组件渲染到屏幕之后执行。你可以把 effect 看作从 React 的纯函数式世界通往命令式世界的逃生通道。

useLayoutEffect(create, deps):

其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。

注意加粗的字段,React 官方的文档其实把两个 hook 的执行时机说的很清楚,下面我们深入到 react 的执行流程中来理解下

问题

  • useEffect 和 useLayoutEffect 的区别?
  • useEffect 和 useLayoutEffect 哪一个与 componentDidMount,componentDidUpdate 的是等价的?
  • useEffect 和 useLayoutEffect 哪一个与 componentWillUnmount 的是等价的?
  • 为什么建议将修改 DOM 的操作里放到 useLayoutEffect 里,而不是 useEffect?

流程

  1. react 在 diff 后,会进入到 commit 阶段,准备把虚拟 DOM 发生的变化映射到真实 DOM 上

  2. 在 commit 阶段的前期,会调用一些生命周期方法,对于类组件来说,需要触发组件的 getSnapshotBeforeUpdate 生命周期,对于函数组件,此时会调度 useEffect 的 create destroy 函数

  3. 注意是调度,不是执行。在这个阶段,会把使用了 useEffect 组件产生的生命周期函数入列到 React 自己维护的调度队列中,给予一个普通的优先级,让这些生命周期函数异步执行

// 可以近似的认为,React 做了这样一步,实际流程中要复杂的多setTimeout(() => {const preDestory = element.destroy;if (!preDestory) prevDestroy();const destroy = create();element.destroy= destroy;
}, 0);
  1. 随后,就到了 React 把虚拟 DOM 设置到真实 DOM 上的阶段,这个阶段主要调用的函数是 commitWork,commitWork 函数会针对不同的 fiber 节点调用不同的 DOM 的修改方法,比如文本节点和元素节点的修改方法是不一样的。

  2. commitWork 如果遇到了类组件的 fiber 节点,不会做任何操作,会直接 return,进行收尾工作,然后去处理下一个节点,这点很容易理解,类组件的 fiber 节点没有对应的真实 DOM 结构,所以就没有相关操作

  3. 但在有了 hooks 以后,函数组件在这个阶段,会同步调用上一次渲染时 useLayoutEffect(create, deps) create 函数返回的 destroy 函数

  4. 注意一个节点在 commitWokr 后,这个时候,我们已经把发生的变化映射到真实 DOM 上了

  5. 但由于 JS 线程和浏览器渲染线程是互斥的,因为 JS 虚拟机还在运行,即使内存中的真实 DOM 已经变化,浏览器也没有立刻渲染到屏幕上

  6. 此时会进行收尾工作,同步执行对应的生命周期方法,我们说的componentDidMount,componentDidUpdate 以及 useLayoutEffect(create, deps) 的 create 函数都是在这个阶段被同步执行

  7. 对于 react 来说,commit 阶段是不可打断的,会一次性把所有需要 commit 的节点全部 commit 完,至此 react 更新完毕,JS 停止执行

  8. 浏览器把发生变化的 DOM 渲染到屏幕上,到此为止 react 仅用一次回流、重绘的代价,就把所有需要更新的 DOM 节点全部更新完成

  9. 浏览器渲染完成后,浏览器通知 react 自己处于空闲阶段,react 开始执行自己调度队列中的任务,此时才开始执行 useEffect(create, deps) 的产生的函数

参考 前端进阶面试题详细解答

解答

useEffect 和 useLayoutEffect 的区别?

useEffect 在渲染时是异步执行,并且要等到浏览器将所有变化渲染到屏幕后才会被执行。

useLayoutEffect 在渲染时是同步执行,其执行时机与 componentDidMount,componentDidUpdate 一致

对于 useEffect 和 useLayoutEffect 哪一个与 componentDidMount,componentDidUpdate 的是等价的?

useLayoutEffect,因为从源码中调用的位置来看,useLayoutEffect的 create 函数的调用位置、时机都和 componentDidMount,componentDidUpdate 一致,且都是被 React 同步调用,都会阻塞浏览器渲染。

useEffect 和 useLayoutEffect 哪一个与 componentWillUnmount 的是等价的?

同上,useLayoutEffect 的 detroy 函数的调用位置、时机与 componentWillUnmount 一致,且都是同步调用。useEffect 的 detroy 函数从调用时机上来看,更像是 componentDidUnmount (注意React 中并没有这个生命周期函数)。

为什么建议将修改 DOM 的操作里放到 useLayoutEffect 里,而不是 useEffect?

可以看到在流程9/10期间,DOM 已经被修改,但但浏览器渲染线程依旧处于被阻塞阶段,所以还没有发生回流、重绘过程。由于内存中的 DOM 已经被修改,通过 useLayoutEffect 可以拿到最新的 DOM 节点,并且在此时对 DOM 进行样式上的修改,假设修改了元素的 height,这些修改会在步骤 11 和 react 做出的更改一起被一次性渲染到屏幕上,依旧只有一次回流、重绘的代价。

如果放在 useEffect 里,useEffect 的函数会在组件渲染到屏幕之后执行,此时对 DOM 进行修改,会触发浏览器再次进行回流、重绘,增加了性能上的损耗。

相关文章:

React的useLayoutEffect和useEffect执行时机有什么不同

我们先看下 React 官方文档对这两个 hook 的介绍,建立个整体认识 useEffect(create, deps): 该 Hook 接收一个包含命令式、且可能有副作用代码的函数。在函数组件主体内(这里指在 React 渲染阶段)改变 DOM、添加订阅、设置定时器、记录日志以…...

C语言中#include<...>和#include“...“的区别

C语言文章更新目录 C语言学习资源汇总,史上最全面总结,没有之一 C/C学习资源(百度云盘链接) 计算机二级资料(过级专用) C语言学习路线(从入门到实战) 编写C语言程序的7个步骤和编程…...

ubuntu本地访问nas

需求 本地磁盘空间太小,本地网络里有个nas,希望将nas作为数据盘挂载到本地使用。 方法1 基于sftp访问nas 首先nas设置时要打开sftp访问功能。 然后用ubuntu桌面访问服务器的功能登录sftp,类似如下指令 sftp://user192.168.0.100 ubuntu下…...

第一章:网络参考模型

一、专业术语 ISO---(International Organization for Standardization)国际标准化组织 OSI---(Open System Interconnection Reference Model)开放式系统互联通信参考模型 IEEE---(Institute of Electrical and Electronics Engi…...

extends in typescript

困惑 初学 ts 时,extends 让我很困惑:有时它代表 扩大 ,有时代表 缩小 。举几个例子说明: 例1: class Animal {} class Dog extends Animal {}这是 js 本身就有的 class 继承语法,很熟悉了。 Dog 是 An…...

如何找回回收站删除的文件

回收站作为删除文件后的临时存放点,只要我们是右键删除或者按delete删除的文件都会存放到这里,所以我们每次清理电脑后,都会清空回收站,这样可以让电脑保持流畅运行。但删除这个操作是很容易出错,很容易把某些重要的文…...

Git系列——Git部署及应用

下面从如下几个方面介绍下其部署及应用:Git服务器搭建Git客户端搭建Git常用命令Git服务器搭建Linux服务器搭建(Centos7.5):一、安装配置SSH(参考XXX)二、检查OS是否自带Git1、git-version //查询版本2、rpm -qa git //查询git详细信息3、yum -y remove x…...

Java多线程(二)--线程相关内容

1.创建线程的几种方式继承 Thread 类;public class MyThread extends Thread { Override public void run() {System.out.println(Thread.currentThread().getName() " run()方法正在执行..."); }实现 Runnable 接口;public class MyRunnable…...

CF1692E Binary Deque 题解

CF1692E Binary Deque 题解题目链接字面描述题面翻译题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1提示思路代码实现题目 链接 https://www.luogu.com.cn/problem/CF1692E 字面描述 题面翻译 有多组数据。 每组数据给出 nnn 个数,每个数为 000 或 1…...

rust方法和关联函数

Rust方法 在大多数面向对象的语言中都存在方法,方法一般和类关联在一起。在Rust中也是类似的,方法和对象总是一起出现。Rust的方法和结构体,枚举,特征一起使用。 定义方法 Rust使用关键字impl来定义方法,例如&#…...

深度学习如何训练出好的模型

深度学习在近年来得到了广泛的应用,从图像识别、语音识别到自然语言处理等领域都有了卓越的表现。但是,要训练出一个高效准确的深度学习模型并不容易。不仅需要有高质量的数据、合适的模型和足够的计算资源,还需要根据任务和数据的特点进行合…...

智慧教室系统--重点设备监控系统

随着教育信息化的不断发展,智慧教室已成为现代教育的重要组成部分。而智慧教室的设备管理和维护也变得越来越重要。一旦智慧教室的重要设备出现故障或异常,将会对教学活动产生不利影响,因此建立智慧教室重点设备监控系统是必要的。一、智慧教…...

Linux中断处理

目录 一、什么是中断 二、中断处理原理 三、中断接口 3.1 中断申请 3.2 中断释放 3.3 中断处理函数原型 四、按键驱动 一、什么是中断 一种硬件上的通知机制,用来通知CPU发生了某种需要立即处理的事件 分为: 1. 内部中断 CPU执行程序的过程中&am…...

python中安装gurobi和pycharm没有语法提示问题解决

安装gurobi第一步 :下载gurobi ( http://www.gurobi.com ) ,需要注册账号第二步、申请License注册如果可以通过校园网, 则直接生成。不能的话,通过网站,发邮件申请 http://www.gurobi.cn/NewsView1.Asp?id4第三、邮件…...

滤波算法:经典卡尔曼滤波

卡尔曼滤波实质上就是基于观测值以及估计值二者的数据对真实值进行估计的过程。预测步骤如图1所示: ​图1 卡尔曼滤波原理流程图 假设我们能够得到被测物体的位置和速度的测量值 ​,在已知上一时刻的最优估计值 ​以及它的协方差矩阵 的条件下&#xff…...

flask框架(下)

文章目录flask框架(下)werkzeug简介请求上下文flask 处理方案回到 wsgi_app 方法中push 源码总结补充flask框架(下) werkzeug简介 Werkzeug是一个WSGI工具包,他可以作为一个Web框架的底层库。这里稍微说一下, werkzeug 不是一个web服务器,也…...

Airbyte架构

作为一款技术复杂的数据集成管道,Airbyte的架构模式非常清晰明了。Airbyte应用模式Airbyte管道架构UI:一个易于使用的图形界面,用于与Airbyte API进行交互。WebApp Server:处理 UI 和 API 之间的连接。Config Store:存…...

anchor box只是先验知识,bounding box是一种过程,ground truth才是标准答案,

anchor boxes是一组提前预定义的边框,这些框的宽高和数据集中目标物体的宽高大体是一致的,换句话说,数据集中的绝大多数物体都能找到与其大小一致的anchor box。 举例来说,如果数据集中包含苹果、猫,那么这组anchor bo…...

带你轻松实现通讯录(C语言版)

文章目录前言通讯录初始化通讯录运行的基本框架和菜单增添联系人删除联系人查找联系人修改联系人信息展示通讯录通讯录联系人个数排序通讯录文件操作储存通讯录信息销毁通讯录整体代码Contacts.hContacts.ctest.c写在最后前言 学习C语言的小伙伴,相信都要经历实现通…...

渗透测试之交换式网络嗅探实验

渗透测试之交换式网络嗅探实验实验目的一、实验原理1.1 网络嗅探器Sniffer的工作原理1.2 网络嗅探器的分类1.3 网络嗅探器Sniffer的作用二、实验环境2.1 操作机器2.2 实验工具Sniffer2.3 安装工具Sniffer三、实验步骤1. 熟悉Sniffer工具的启动2. 进行监听3. 熟悉Sniffer工具的介…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...

三体问题详解

从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...

Vue ③-生命周期 || 脚手架

生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...

mac:大模型系列测试

0 MAC 前几天经过学生优惠以及国补17K入手了mac studio,然后这两天亲自测试其模型行运用能力如何,是否支持微调、推理速度等能力。下面进入正文。 1 mac 与 unsloth 按照下面的进行安装以及测试,是可以跑通文章里面的代码。训练速度也是很快的。 注意…...

Java后端检查空条件查询

通过抛出运行异常&#xff1a;throw new RuntimeException("请输入查询条件&#xff01;");BranchWarehouseServiceImpl.java // 查询试剂交易&#xff08;入库/出库&#xff09;记录Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…...

DAY 45 超大力王爱学Python

来自超大力王的友情提示&#xff1a;在用tensordoard的时候一定一定要用绝对位置&#xff0c;例如&#xff1a;tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾&#xff1a; tensorboard的发展历史和原理tens…...

6.9本日总结

一、英语 复习默写list11list18&#xff0c;订正07年第3篇阅读 二、数学 学习线代第一讲&#xff0c;写15讲课后题 三、408 学习计组第二章&#xff0c;写计组习题 四、总结 明天结束线代第一章和计组第二章 五、明日计划 英语&#xff1a;复习l默写sit12list17&#…...