useEffect的基础知识和底层机制

news2024/11/16 21:57:30

useEffect 是 React 中一个重要的 Hook,用来处理组件的副作用操作。它的基础知识包括两个方面:执行时机和参数。

执行时机:

useEff ect 的执行时机包括两种情况:

  1. 组件挂载时,即第一次渲染之后。
  2. 组件更新时,即组件的 props 或状态发生变化时。

参数:

useEffect 接收两个参数:一个函数和一个依赖数组。

  1. 函数:这个函数会在组件的挂载和更新时被调用,它可以包含一些副作用操作,比如修改 DOM、发送网络请求等等。
  2. 依赖数组:这个数组是一个可选参数,用来指定 useEffect 的依赖项。如果一个组件中需要多次调用 useEffect,那么每次调用都需要指定依赖数组。当依赖数组中的任何一个值发生变化时,才会触发 useEffect 的重新执行。如果依赖数组为空,则表示 useEffect 没有任何依赖,只会在组件挂载和卸载时执行。

写法

  1. useEffect(callback):font color=red>这个参数表示只要组件发生更新,就会执行回调函数 callback,包括组件挂载时的初始化和后续状态或属性的更新。如果不需要依赖任何状态或属性,相当于类组件中的 componentDidMountcomponentDidUpdate 的合并。
  2. useEffect(callback, []):这个参数表示只在组件挂载时执行一次回调函数 callback,不会在组件更新时执行。这个参数当中传入的空数组 [] 表示没有任何依赖,因此只有在组件挂载时才会执行。
  3. useEffect(callback, [state1, state2, ...]) 这个参数表示在组件挂载时执行一次回调函数 callback,之后只有 state1state2 等指定的依赖状态发生改变时才会执行回调函数。如果多个状态都需要依赖,可以在数组中传入多个状态名称。
   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.useLayoutEffectuseEffect 很相似,都是 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 对象。
  • 执行更新队列中已记录的所有组件的生命周期方法,包括 shouldComponentUpdaterendergetSnapshotBeforeUpdatecomponentDidUpdate 等方法。
  • 基于 Virtual DOM 树比较上一次渲染时的 virtual DOM 树和本次渲染时的 virtual DOM 树,找出两棵树之间的差异,并记录需要更新的 DOM 对象的最小集合。
  • 在浏览器空闲时间内执行更新和重绘操作,优化更新过的 DOM 对象,尽可能减少页面的重排和重绘的次数,提高页面的性能和响应速度。

2. useLayoutEffect 和 useEffect 的区别

  • useLayoutEffect 与 useEffect 在实现上是类似的,不同之处在于 useLayoutEffect 的回调函数会在 DOM 更新之后,浏览器执行绘制之前被调用,而 useEffect 的回调函数则是在浏览器执行绘制之后被调用。
  • useLayoutEffect 在执行回调函数时会产生阻塞效果,可能会导致页面感觉卡顿,而 useEffect 则不会产生这种阻塞效果。
  • 因此,如果回调函数需要操作 DOM 或者进行某些与界面交互相关的操作,可以考虑使用 useLayoutEffect;如果不需要进行交互,或者交互操作可以忍受一定的延迟,可以使用 useEffect。

3. 视图更新如何影响性能和用户体验

  • 视图更新是一种相对费时的操作,如果更新操作过于频繁或过于复杂,可能会影响页面的性能和响应速度,甚至引起页面卡顿等问题。
  • 对于频繁进行更新的组件,可以考虑使用 React.memouseMemouseCallback 等优化方式,避免重复的计算和更新。
  • 对于需要操作 DOM 或进行其他交互操作的组件,要特别注意使用 useLayoutEffectuseEffect 时的延迟问题和阻塞效果,避免影响页面的流畅度和响应速度。同时,也要考虑好性能和用户体验之间的平衡,避免过度追求优化而影响用户的体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/634695.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pandas---Series与DataFrame索引、切片;多层索引、索引的堆叠

1. Series的索引和切片 1.1 Series的索引: 可以使用中括号取单个索引(此时返回的是元素类型),或者中括号里一个列表取多个索引(此时 返回的仍然是一个Series类型)。分为显示索引和隐式索引: …

后台服务接口间大文件的流式发送和读取

文章目录 介绍代码设计代码参考客户端代码服务器端代码测试实例 介绍 使用HTTP协议进行数据流式传输是一种常见的方法。对于大文件数据传输可以使用HTTP的chunked编码或使用多部分响应来实现数据流式传输。 【HTTP的chunked编码】在发送数据的服务中,可以将数据切分…

postman接口测试学习笔记(非常详细)

目录 引言 1. 资源 2.接口测试 3. 接口返回数据和JSON详解 4.接口测试协议 5.企业接口测试的流程和方案 6. 接口测试工具以及Postman介绍 7.Postman之内置的动态参数和应用 8.接口关联 引言 接口测试工具如何选择?在我看来,Postman是一个非常值…

电商--红包活动总结

文章目录 背景表结构设计实现流程流程图流程解析流程优化 背景 这是一个来自于NFT电商项目,这是个营销策略的需求,为了快狠准,短期内刺激消费,拉动销售增加购买量。运营人员可以在平台创建红包,并且设置该红包的发放时…

Android系统视角下对APK的分析(1)- 静态分析APK文件

声明 以Android手机用户角度来看,安装各式各样的APP,基本就是从应用市场上 “搜索->下载->安装” 三连。而对Android系统来说,这就是个大工程了,因为对Android系统来说APK是“外来户”,如何安装它、有限制地支持…

【用户认证】密码加密,用户状态保存,cookie,session,token

相关概念 认证与授权 认证(authentication )是验证你的身份的过程,而授权(authorization)是验证你有权访问的过程 用户认证的逻辑 获取用户提交的用户名和密码根据用户名,查询数据库,获得完…

redis知识复习

redis知识复习 redis基础知识redis的认识一. 非关系型数据库 与 传统数据库 的区别二. 安装redis并设置自启动三. 熟悉命令行客户端四.熟悉图形化工具RDM redis的命令与数据结构一. 数据结构介绍二. redis通用命令(熟练掌握) redis的Java客户端一. Jedis…

文心一言 VS 讯飞星火 VS chatgpt (38)-- 算法导论5.4 2题

二、假设我们将球投入到b个箱子里,直到某个箱子中有两个球。每一次投掷都是独立的并且每个球落入任何箱子的机会均等。请问投球次数期望是多少? 文心一言: 这是一个典型的鸽巢原理(Pigeonhole Principle)问题。假设每次投球时&…

2023年上半年系统分析师下午真题及答案解析

试题一(25分) (试题一为必答题,试题二~五选答两题) 某软件公司拟开发一套汽车租赁系统,科学、安全和方便的管理租赁公司的各项业务,提高公司效率,提升利用率。注册用户在使用系统进行车辆预约时需执行以下操作:(a)用…

从0-1一起学习live555设计思想之二 RTSP交互过程

流媒体服务系列 文章目录 流媒体服务系列前言一、OPTION二、DESCRIBE三、SETUP四、PLAY总结前言 本篇文章通过代码去分析rtsp交互过程与工作原理。由于live555的继承关系太过复杂,所以做了个图简单记录一下与h264文件传输相关的类继承关系。 一、OPTION OPTION比较简单,就…

【调制BFSK】二进制频移键控FSK的数字调制(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

ARM学习(22)断点认识以及调试

笔者来聊聊断点以及断点的调试 1、断点原理 断电的原理一般分为两种,插入断点指令或者利用硬件调试寄存器进行断点。 前者程序如果在RAM(SRAM、DDR)上,则调试器可以直接在断点地址处插入断点指令,例如BKPT&#xff0…

python自动化测试-自动化基本技术原理

1 概述 在之前的文章里面提到过:做自动化的首要本领就是要会 透过现象看本质 ,落实到实际的IT工作中就是 透过界面看数据。 掌握上面的这样的本领可不是容易的事情,必须要有扎实的计算机理论基础,才能看到深层次的本质东西。 …

家用电器-空调制冷、制热、除霜、除湿、换新风的基本原理及实现讲解

目录 一、空调历史 二、空调的作用 三、空调类型 四、基本原理 4.1 制冷过程 4.2 制热过程 4.3 除霜过程 4.4 除湿过程 4.5 换气过程 五、电路控制系统 六、核心部件 七、基本指标 1)气候类型 2)额定制冷量 3)能效比 八、市场…

4年功能庸庸碌碌,进阶自动化测试拿到了24k,测试之路不再平凡...

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 手工测试如何进阶…

多业务聚合查询设计思路与实践

文章目录 [toc] 1.需求2.方案2.1 方案架构图2.2 选用flink-cdc的原因 3.实践3.1 环境准备3.3 es集群搭建3.4 flink1.14.0环境搭建3.5 准备sql和jar包3.5.1[创建mysql的flink用户并授权](https://ververica.github.io/flink-cdc-connectors/master/content/connectors/mysql-cdc…

【树形DP+直径思想】代码源每日一题div1 三进制循环

三进制循环 - 题目 - Daimayuan Online Judge 题意: 思路: 有点像树的直径 回顾一下我们是怎么求直径的:维护根节点到其子树上的点的最大距离和次大距离,然后答案就是统计所有结点的次大值最大值 的 最大值 这道题也是一样的&a…

C盘爆满时的几个救命无害清理技巧

其实网上也有很多清理C盘的方法 但是很多就是为了弄成空间 不讲原理 也不计后果 很可能坑惨小伙伴 可以看到 我电脑的C盘都已经读红条了 非常危险 对了 可能有些朋友的电脑上没有此电脑的选项 我们可以在桌面上右键选择 个性化 找到 主题 并选择 向下拉 找到 桌面图标设置 …

经验总结:13 条自动化测试框架设计原则!

1.代码规范 测试框架随着业务推进,必然会涉及代码的二次开发,所以代码编写应符合通用规范,代码命名符合业界标准,并且代码层次清晰。特别在大型项目、多人协作型项目中,如果代码没有良好的规范,那么整个框…

微服务之负载均衡

Informal Essay By English I wish the students of the college entrance examination can win the gold toad and win the title of the gold list 参考书籍:“凤凰架构” 负载均衡(load balance) 负载平衡是指在一组后端服务器&#xf…