useEffect的基础知识和底层机制
useEffect 是 React 中一个重要的 Hook,用来处理组件的副作用操作。它的基础知识包括两个方面:执行时机和参数。
执行时机:
useEff ect 的执行时机包括两种情况:
- 组件挂载时,即第一次渲染之后。
- 组件更新时,即组件的 props 或状态发生变化时。
参数:
useEffect 接收两个参数:一个函数和一个依赖数组。
- 函数:这个函数会在组件的挂载和更新时被调用,它可以包含一些副作用操作,比如修改 DOM、发送网络请求等等。
- 依赖数组:这个数组是一个可选参数,用来指定 useEffect 的依赖项。如果一个组件中需要多次调用 useEffect,那么每次调用都需要指定依赖数组。当依赖数组中的任何一个值发生变化时,才会触发 useEffect 的重新执行。如果依赖数组为空,则表示 useEffect 没有任何依赖,只会在组件挂载和卸载时执行。
写法
useEffect(callback)
:font color=red>这个参数表示只要组件发生更新,就会执行回调函数callback
,包括组件挂载时的初始化和后续状态或属性的更新。如果不需要依赖任何状态或属性,相当于类组件中的componentDidMount
和componentDidUpdate
的合并。useEffect(callback, [])
:这个参数表示只在组件挂载时执行一次回调函数callback
,不会在组件更新时执行。这个参数当中传入的空数组[]
表示没有任何依赖,因此只有在组件挂载时才会执行。useEffect(callback, [state1, state2, ...])
: 这个参数表示在组件挂载时执行一次回调函数callback
,之后只有state1
、state2
等指定的依赖状态发生改变时才会执行回调函数。如果多个状态都需要依赖,可以在数组中传入多个状态名称。
useEffect( ()=>{return ()=>{//返回的小函数,会在组件释放的时候执行//如果组件更新,会把上一次函数执行,返回的小函数执行console.[log( '@4' ,num );});
需要注意的是,如果在 callback
中进行了一些异步操作,比如发起网络请求,需要在组件被销毁时主动取消这些异步操作,以防止内存泄漏。可以使用 useEffect
返回的清除函数来实现这个功能。例如:
useEffect(() => {const fetchData = async () => {// 发起异步请求}fetchData();return () => {// 取消异步请求}
}, [state1])
在这个例子中,fetchData
函数是一个异步操作,会在组件挂载和 state1
发生改变时被调用。在 useEffect
的回调函数中返回了一个清除函数,该函数会在组件被销毁时调用,用来取消异步请求操作。
底层机制:
基于effect链表实行!!!是异步的,effect
链表是指在一个 useEffect
钩子中,可以有多个副作用函数(或称为 effect 函数)。这些副作用函数会被按照它们声明的顺序依次执行,形成一条链表。当组件更新时,这些函数也会被按照它们声明的顺序依次执行。
useLayoutEffect和useEffect的细节
1.需求:在num大于5的时候我们再ueseffect
if ( num > 5){
useEffect( ( ) => {
lconsole.log ( 'OK');
});
}
会报错useEffect必须在函数的最外层上下文中调用,不能把其嵌入到条件判断、循环等操作语句中,应该这样做
useEffect(() => {if (num > 5) {console.log('OK');}
}, [num]);
2.模拟从服务器异步获取数据
错误写法:
在这个例子中,这里返回的是一个promise实例,而不是一个函数,我们试图在 useEffect
中使用 async/await
,然后在函数体内调用 queryData
函数获取数据并打印到控制台上。但是你需要注意,useEffect
钩子中的副作用函数必须是同步的函数(或者返回一个清除函数的函数),而 async/await
函数是异步的函数,因此不能直接在 useEffect
中使用。
可以将副作用函数的主体逻辑封装到一个单独的函数中,然后在 useEffect
中调用这个函数:
const fetchData = async () => {let data = await queryData();console.log('成功: ', data);
};useEffect(() => {fetchData();return () => {// 在组件卸载前,清除副作用console.log('清除 fetchData 副作用');};
}, []);
在这个例子中,我们将获取数据并打印到控制台的操作封装到了 fetchData
函数中,这个函数是一个异步的 async
函数。然后我们在 useEffect
中调用了这个 fetchData
函数。由于 useEffect
存在异步特性,因此不会阻塞其它的组件渲染,而副作用 fetchData
会在组件初次渲染时被调用,并且不会被重复执行(因为依赖列表是空的)。
需要注意的是,我们不能直接将 fetchData
函数放在 useEffect
中调用,而是需要先将它定义成一个变量。因为在 useEffect
中定义的函数会被作为闭包存储,并且它们的引用关系不会随着组件更新而改变。如果我们直接在 useEffect
中定义 async/await
函数,那么这个函数的引用关系会在每个组件更新时被重置,从而无法实现我们的预期效果。
3.什么是副作用函数??
根据上一个问题,fetchData
函数中包含了异步操作,比如网络请求,这些异步操作具有副作用。因此 fetchData
函数被视为具有副作用的函数。
在函数式编程语言中,副作用是指函数对外部环境造成的影响,这些影响可能会改变系统状态或返回一些不可预测的结果。在 JavaScript 中,一些常见的副作用包括修改全局状态、改变 DOM、读写本地存储、发出网络请求等等。
由于副作用的不确定性和可变性,React 为我们提供了钩子函数,例如 useEffect
,以及一些限制和规范,来管理和控制副作用。在 React 中,我们应该尽量避免直接操作 DOM,而应该通过钩子函数和状态管理来更新视图和响应用户操作。
useLayoutEffect
1.useLayoutEffect
和 useEffect
很相似,都是 React 提供的用于处理副作用的钩子函数。它们的主要区别在于执行时间不同。
useLayoutEffect
在第二步结束的时候渲染,useEffect
在第三步结束的时候渲染
2.useEffect
会在浏览器完成绘制后,即组件渲染到页面上后异步执行。也就是说,可能会在用户看到更新前看到旧的 UI。而 useLayoutEffect
会在浏览器绘制之前同步执行,useLayoutEffect会阻止浏览器渲染真实DOM,优先执行Effect链表中的callback;
这里的渲染是指绘制,useLayoutEffect 执行时,组件返回的 JSX 已经被渲染成 DOM,但 DOM 还没有完成 layout,也就是还没有完成测量和定位。相对于 useEffect,useLayoutEffect 触发的时机更早,可以拿到更快更准确的测量值,同时又避免了闪烁和触发重渲染的问题。因此可以在 useLayoutEffect 中进行对真实 DOM 的操作。,确保无论是 React 还是 DOM 视图都是最新的,即用户看到的 UI 是最新的。
如果你需要在更新 DOM 前同步更新某些组件或页面状态并且必须优先更新,可以使用 useLayoutEffect
。如果不需要优先更新或状态更新较慢也不会影响用户体验,可以使用 useEffect
。
需要注意,由于 useLayoutEffect
的同步执行,如果钩子函数的操作逻辑较耗时,则可能会导致页面卡顿或延迟加载。因此,应该谨慎使用 useLayoutEffect
,避免出现性能问题。
渲染次数问题:
如果在callback函数中又修改了状态值「视图又要更新」
1.useEffect:浏览器肯定是把第一次的真实已经绘制了,再去渲染第二次真实DOM
2.useLayoutEffect:浏览器是把两次真实DOM的渲染,合并在一起渲染的
总结
1. 视图更新的步骤
- 将 JSX 编译为
createElement
格式并调用,创建出 Virtual DOM。 - 基于
root.render
方法将 Virtual DOM 转换为真实 DOM 对象。 - 执行更新队列中已记录的所有组件的生命周期方法,包括
shouldComponentUpdate
、render
、getSnapshotBeforeUpdate
和componentDidUpdate
等方法。 - 基于 Virtual DOM 树比较上一次渲染时的 virtual DOM 树和本次渲染时的 virtual DOM 树,找出两棵树之间的差异,并记录需要更新的 DOM 对象的最小集合。
- 在浏览器空闲时间内执行更新和重绘操作,优化更新过的 DOM 对象,尽可能减少页面的重排和重绘的次数,提高页面的性能和响应速度。
2. useLayoutEffect 和 useEffect 的区别
- useLayoutEffect 与 useEffect 在实现上是类似的,不同之处在于 useLayoutEffect 的回调函数会在 DOM 更新之后,浏览器执行绘制之前被调用,而 useEffect 的回调函数则是在浏览器执行绘制之后被调用。
- useLayoutEffect 在执行回调函数时会产生阻塞效果,可能会导致页面感觉卡顿,而 useEffect 则不会产生这种阻塞效果。
- 因此,如果回调函数需要操作 DOM 或者进行某些与界面交互相关的操作,可以考虑使用 useLayoutEffect;如果不需要进行交互,或者交互操作可以忍受一定的延迟,可以使用 useEffect。
3. 视图更新如何影响性能和用户体验
- 视图更新是一种相对费时的操作,如果更新操作过于频繁或过于复杂,可能会影响页面的性能和响应速度,甚至引起页面卡顿等问题。
- 对于频繁进行更新的组件,可以考虑使用
React.memo
、useMemo
、useCallback
等优化方式,避免重复的计算和更新。 - 对于需要操作 DOM 或进行其他交互操作的组件,要特别注意使用
useLayoutEffect
和useEffect
时的延迟问题和阻塞效果,避免影响页面的流畅度和响应速度。同时,也要考虑好性能和用户体验之间的平衡,避免过度追求优化而影响用户的体验。
相关文章:

useEffect的基础知识和底层机制
useEffect 是 React 中一个重要的 Hook,用来处理组件的副作用操作。它的基础知识包括两个方面:执行时机和参数。 执行时机: useEff ect 的执行时机包括两种情况: 组件挂载时,即第一次渲染之后。组件更新时ÿ…...

chatgpt赋能python:Python中如何加空格
Python中如何加空格 Python是一门广泛应用于科学计算、数据分析、人工智能、Web开发等领域的高级编程语言。在Python编程过程中,经常需要使用到空格,以实现程序的格式化和美观,同时也有助于提高代码的可读性和可维护性。本文主要介绍Python中…...

软件测试之路已不再是坦途
去年下半年才跳了槽,过程非常顺利,没有经历大家所说的工作荒的境地,所以一直没有直观地感受到软件测试就业形势到底有多严峻。 近来看到一些机构频频发出某某测试员在糟糕的就业形势下逆袭拿下XXW的某厂offer,然后推荐测试进阶课…...

扫雷——C语言实现
扫雷 文章目录 扫雷实现代码什么是扫雷基本功能实现显示选择菜单定义几个二维数组?确定数组大小初始化数组布置地雷打印展示数组排查地雷记录指定区域周围地雷的个数判断排雷成功排查地雷实现代码 基本功能的实现代码和效果展示 拓展功能简化游戏界面改变字体颜色实…...

CSS基础学习--6 CSS Text(文本)
一、文本颜色 color:red; 颜色属性被用来设置文字的颜色。 颜色是通过CSS最经常的指定: 十六进制值 - 如: #FF0000一个RGB值 - 如: RGB(255,0,0)颜色的名称 - 如: red body {color:red;} h1 {color:#00ff00;} h2 {color:rgb(255,0,0);} 二、文本的…...

高精度电压源的应用场合有哪些
高精度电压源是一种能够提供恒定、稳定电压输出的设备,被广泛应用于各种领域。高精度电压源是现代电力、通信、控制等领域中重要的测试仪器之一,其主要功能是提供稳定可靠的直流或交流电源,并具有高精度和高分辨率的特点。在实际应用中&#…...
Android约束布局
一、嵌套布局效率可能很低。 在 Android 开发中,我们常常需要使用嵌套布局来实现某些较复杂的界面效果。但是嵌套层级太深会带来一些问题,主要包括: 视图层级过深,导致内存占用过高和性能下降。Android 需要为每个 View 对象分配内存,嵌套层级过深会创建很多 View 对象,占用较…...

selenium基础语法
文章目录 selenium基础语法1.定位页面元素2.元素的操作1) 模拟键盘输入(send_keys)2) 点击操作(click)3) 清除去对象输入的文本内容(clear)4) 获取文本(gettext) 3. 等待4. 信息打印5. 窗口6. 导航7. 弹窗8. 鼠标和弹窗9.选择框10.文件上传11.屏幕截图 selenium基础语法 1.定位…...

运行后端SpringBoot项目
目录 一、注册微信开发者账号 1. 注册开发者账号 2. 获取appid和密钥 二、开通腾讯云TRTC服务 1. TRTC业务介绍 2. 为什么不使用阿里云的实时音视频服务,偏要选用腾讯云TRTC服务? 3. 开通TRTC服务 4. 领取TRTC的AppID和密钥 三、导入 emos-api …...
#如何对待工作中的失误?# 如何对待工作与生活中的失误——一些不成熟的忠告
关于如何对待工作与生活中的失误的忠告 1.在面对失误而带来的指责和沮丧时,应该如何做?1.1 正确认识失误1.2 处理失误后情绪与问题的途径1.2.1 接受现实,不要否认错误1.2.2 不要过度臆想1.2.3 安排调整情绪的时间1.2.4 向他人寻求帮助 2.发生…...

Shell脚本文本三剑客之awk编辑器
目录 一、awk简介 二、awk工作原理 三、awk命令格式 四、awk命令的使用 1.print操作按行输出文本 2.print操作按字段截取输出文本 3.使用BEGIN和END指定操作 4.使用管道符号,双引号调用shell命令 5.使用操作getline 6.使用操作OFS 7.配合数组使用 一、…...
Focal Loss介绍
目录 前言一. Focal Loss二. 总结 前言 在目标检测算法中,我们会经常遇到Focal Loss这个东西,今天我们就来简单的分下下这个损失。 一. Focal Loss 在深度学习训练的时候,在遇到目标类别不平衡时,如果直接计算损失函数࿰…...

【数据结构与算法】04 哈希表 / 散列表 (哈希函数、哈希冲突、链地址法、开放地址法、SHA256)
一种很好用,很高效,又一学就会的数据结构,你确定不看看? 一、哈希表 Hash Table1.1 核心概念1.2 哈希函数 Hash Function1.3 哈希冲突 Hash Collision1.4 哈希冲突解决1.41 方法概述1.42 链地址法 Separate Chaining1.43 开放寻址…...
每日一道面试题之介绍一下Java的序列化和反序列化!
什么是序列化? 序列化是将对象转换为容易传输的格式的过程,它是一种用来处理对象流的机制,将对象的内容流化,从而使流化后的对象传输于网络之间,以便它们可以在网络上传输或在磁盘上存储。反序列化是将序列化后的数据…...

Netty实战(十一)
预置的ChannelHandler和编解码器(一)HTTP和SSL/TLS的添加和使用 一、SSL和TLS添加二、基于Netty的HTTP程序2.1 HTTP解码器、编码器和编解码器2.2 聚合HTTP消息2.3 HTTP压缩 一、SSL和TLS添加 作为一个通讯框架,通讯数据的安全性也是不可或缺的…...
Qos服务质量、心跳机制、保留消息,遗嘱信息,用户密码认证
这里写目录标题 Qos服务质量使用ESP8266接收QoS1的MQTT消息保留消息(retainFlag)心跳机制遗嘱信息 Qos服务质量 若想实现QoS>0,订阅端连接服务端时cleanSession需要设置为false,订阅端订阅主题时QoS>0,发布端发…...
MATLAB 之 线性方程组求解
这里写目录标题 一、线性方程组求解1. 线性方程组的直接解法1.1 利用左除运算符的直接解法1.2 利用矩阵的分解求解线性方程组 2. 线性方程组的迭代解法2.1 Jacobi 迭代法2.2 Gauss-Serdel 迭代法 3. 求线性方程的通解 一、线性方程组求解 在 MATLAB 中,关于线性方程…...

华为OD机试真题 Java 实现【字符串序列判定】【2022Q4 100分】,附详细解题思路
一、题目描述 输入两个字符串a和b,都只包含英文小写字母。a长度<=100,b长度<=500,000。 判定a是否是b的有效子串。 判定规则: a中的每个字符在b中都能找到(可以不连续),且a在b中字符的前后顺序与a中顺序要保持一致。 (例如,a=”qwt”是b=”qwerty”的一个子…...

taro使用小记 —— 持续更新
目录 1、在 taro 中使用 axios2、在 taro 中添加全局组件自动引入和方法自动引入3、在 taro 中使用 pinia 1、在 taro 中使用 axios taro 3.6 版本已经支持了网络请求库。 需安装插件 tarojs/plugin-http 使用和注意事项说明: https://www.npmjs.com/package/taroj…...

【LeetCode】110. 平衡二叉树
110. 平衡二叉树(简单) 思路 对二叉树做先序遍历,从底至顶返回子树最大高度,若判定某子树不是平衡树则“剪枝”直接向上返回。 递归返回值: 当节点 root 左、右子树的高度差 > 1:返回 -1,代…...

dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...