react中hooks之useEffect 用法总结
1. 什么是函数的副作用(Side Effects)
副作用是指在组件渲染过程中,除了返回 JSX 之外的其他操作,例如:
- 数据获取(API 调用)
- 订阅数据源
- 手动修改 DOM
- 设置定时器
- 存储数据
- 日志记录
纯函数是特定的输入只会有特定的输出,也就是说组件会输出特定的DOM给浏览器渲染,除去这份逻辑以外的操作就称之为副作用,比如获取数据,监听,订阅等等
2. useEffect 的执行时机
2.1 省略依赖项
useEffect(() => {console.log('每次渲染都会执行');
}); // 没有依赖项数组
- 组件每次渲染都会执行
- 包括首次渲染和后续更新
2.2 指定依赖项
useEffect(() => {console.log(`count 发生变化:${count}`);
}, [count]); // 依赖于 count
- 首次渲染时执行
- 依赖项发生变化时执行
- 多个依赖项时,任意一个变化都会触发执行
2.3 空数组依赖项
useEffect(() => {console.log('只在组件挂载时执行一次');
}, []); // 空数组
- 仅在组件首次渲染(挂载)时执行一次
- 类似于 class 组件的 componentDidMount
3. 常见问题和最佳实践
3.1 避免依赖项循环
// ❌ 错误示例:造成无限循环
function BadExample() {const [count, setCount] = useState(0);useEffect(() => {setCount(count + 1); // 直接修改依赖项}, [count]);return <div>{count}</div>;
}// ✅ 正确示例:使用函数式更新
function GoodExample() {const [count, setCount] = useState(0);useEffect(() => {setCount(prevCount => prevCount + 1);}, []); // 不需要依赖项return <div>{count}</div>;
}
3.2 分离关注点
function UserProfile({ userId }) {const [user, setUser] = useState(null);const [posts, setPosts] = useState([]);// ✅ 分开声明不同功能的 useEffectuseEffect(() => {// 获取用户信息fetchUser(userId).then(setUser);}, [userId]);useEffect(() => {// 获取用户帖子fetchUserPosts(userId).then(setPosts);}, [userId]);return (<div><UserInfo user={user} /><UserPosts posts={posts} /></div>);
}
4. 清除副作用
4.1 清理函数的执行时机
清理函数会在以下情况执行:
- 组件卸载时
- 下一次 effect 执行前
4.2 事件监听示例
function WindowWidth() {const [width, setWidth] = useState(window.innerWidth);useEffect(() => {const handleResize = () => setWidth(window.innerWidth);// 添加事件监听window.addEventListener('resize', handleResize);// 清理函数return () => {window.removeEventListener('resize', handleResize);};}, []); // 空依赖数组,只在挂载和卸载时执行return <div>Window width: {width}</div>;
}
4.3 定时器示例
function Timer() {const [count, setCount] = useState(0);useEffect(() => {const timer = setInterval(() => {setCount(c => c + 1);}, 1000);// 清理函数:组件卸载时清除定时器return () => clearInterval(timer);}, []); // 空依赖数组return <div>Count: {count}</div>;
}
4.4 数据订阅示例
function DataSubscriber({ dataSource }) {const [data, setData] = useState(null);useEffect(() => {let isSubscribed = true;const handleData = (newData) => {if (isSubscribed) {setData(newData);}};// 订阅数据源const subscription = dataSource.subscribe(handleData);// 清理函数:取消订阅return () => {isSubscribed = false;subscription.unsubscribe();};}, [dataSource]); // 依赖于 dataSourcereturn <div>{data ? <DataView data={data} /> : 'Loading...'}</div>;
}
4.5 WebSocket 连接示例
function WebSocketComponent({ url }) {const [messages, setMessages] = useState([]);useEffect(() => {const ws = new WebSocket(url);ws.onmessage = (event) => {setMessages(prev => [...prev, event.data]);};// 清理函数:关闭 WebSocket 连接return () => {ws.close();};}, [url]);return (<div>{messages.map((msg, index) => (<div key={index}>{msg}</div>))}</div>);
}
5. 实际应用场景
5.1 表单自动保存
function AutoSaveForm() {const [content, setContent] = useState('');const [saving, setSaving] = useState(false);useEffect(() => {// 防抖处理const timeoutId = setTimeout(() => {if (content) {setSaving(true);saveContent(content).then(() => setSaving(false));}}, 1000);return () => clearTimeout(timeoutId);}, [content]);return (<div><textareavalue={content}onChange={e => setContent(e.target.value)}/>{saving && <span>Saving...</span>}</div>);
}
5.2 实时搜索
function SearchComponent() {const [query, setQuery] = useState('');const [results, setResults] = useState([]);useEffect(() => {// 避免空查询if (!query.trim()) {setResults([]);return;}const abortController = new AbortController();async function fetchResults() {try {const response = await fetch(`/api/search?q=${query}`,{ signal: abortController.signal });const data = await response.json();setResults(data);} catch (error) {if (error.name === 'AbortError') {// 忽略中止的请求错误return;}console.error('搜索出错:', error);}}const timeoutId = setTimeout(fetchResults, 300);// 清理函数:取消请求和清除定时器return () => {clearTimeout(timeoutId);abortController.abort();};}, [query]);return (<div><inputvalue={query}onChange={e => setQuery(e.target.value)}placeholder="搜索..."/><ul>{results.map(result => (<li key={result.id}>{result.title}</li>))}</ul></div>);
}
6. 最佳实践总结
- 保持 effect 函数简洁,专注于单一功能
- 合理使用依赖项,避免不必要的执行
- 始终清理副作用,防止内存泄漏
- 使用条件语句控制 effect 的执行
- 考虑使用自定义 Hook 封装常用的副作用逻辑
- 在开发环境下使用 ESLint 的 exhaustive-deps 规则检查依赖项
- 使用 useCallback 和 useMemo 优化依赖项
通过合理使用 useEffect,我们可以优雅地处理组件的副作用,实现更复杂的交互逻辑,同时保持代码的可维护性和性能。
相关文章:
react中hooks之useEffect 用法总结
1. 什么是函数的副作用(Side Effects) 副作用是指在组件渲染过程中,除了返回 JSX 之外的其他操作,例如: 数据获取(API 调用)订阅数据源手动修改 DOM设置定时器存储数据日志记录 纯函数是特定的…...
小型、中型无人机执照学习和考试区别详解
小型、中型无人机执照的学习和考试在多个方面存在区别。以下是对两者的详细对比: 一、定义与适用范围 1. 小型无人机: 通常指起飞重量在7kg至25kg之间的无人机。 适用于多种应用场景,包括商业飞行、航拍、农业植保等。 必须持有民航局无人…...
【Go】Go Gin框架初识(一)
1. 什么是Gin框架 Gin框架:是一个由 Golang 语言开发的 web 框架,能够极大提高开发 web 应用的效率! 1.1 什么是web框架 web框架体系图(前后端不分离)如下图所示: 从上图中我们可以发现一个Web框架最重要…...
计算机网络的五层协议
计算机网络的五层协议 计算机网络的五层协议模型包括物理层、数据链路层、网络层、传输层和应用层,每一层都有其特定的功能和相关的协议。1 物理层:负责传输原始的比特流,通过线路(有线或无线)将数据转换为…...
QT中,在子线程中更新UI,会出现哪些问题,如何避免这种情况发生。
在Qt中,直接从子线程更新UI(用户界面)通常会导致各种问题,主要是因为Qt的UI组件(如QWidget及其子类)并不是线程安全的。具体来说,可能会出现以下问题: 崩溃和未定义行为:…...
C++并发编程之多线程环境下使用无锁数据结构的重要准则
在多线程环境中使用无锁数据结构(Lock-Free Data Structures)能够显著提高程序的并发性能,因为它们避免了传统锁机制带来的竞争和阻塞问题。然而,无锁编程本身也带来了许多挑战,如内存管理、数据一致性和正确性等问题。…...
Vue篇-07
Vue UI组件库 一、移动端常用的UI组件库 1.1、Vant 1.2、Cube UI 1.3、Mint UI 二、PC端常用的UI组件库 2.1、Element UI Element - The worlds most popular Vue UI framework 安装: 按需引入: 135_尚硅谷Vue技术_element-ui按需引入_哔哩哔哩_b…...
Zookeeper 数据迁移实战:基础环境搭建与高效迁移方案全览
文章目录 一、Zookeeper数据迁移简介二、迁移zookeeper数据基础环境三、利用快照迁移zookeeper数据1、Node1最新的zk快照文件和日志文件2、将被迁移方node2的zookeeper的集群全部stop3、将源node1集群数据和日志拷贝到指定目录下4、验证优先启动拷贝的数据、日志的zookeeper节点…...
内联变量(inline variables):在多个文件中共享全局常量
在 C17 中,引入了 内联变量(inline variables) 的概念,可以用于在多个文件中共享全局常量。内联变量允许在头文件中定义变量,而不会导致链接错误(如重复定义)。这种方式非常适合用于定义跨多个文…...
WOA-CNN-LSTM-Attention、CNN-LSTM-Attention、WOA-CNN-LSTM、CNN-LSTM四模型对比多变量时序预测
WOA-CNN-LSTM-Attention、CNN-LSTM-Attention、WOA-CNN-LSTM、CNN-LSTM四模型对比多变量时序预测 目录 WOA-CNN-LSTM-Attention、CNN-LSTM-Attention、WOA-CNN-LSTM、CNN-LSTM四模型对比多变量时序预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 基于WOA-CNN-LSTM-A…...
【kubernetes】K8S节点状态的维护
1 节点状态 节点是K8S集群中的一类重要资源,节点的状态通常可以作为判断集群异常的重要手段。 为了展示节点在各方面的健康程度,在kubectl describe node k8s-master的输出结果中的Conditions部分可以查看k8s-master节点的一些状态数据: N…...
工业视觉2-相机选型
工业视觉2-相机选型 一、按芯片类型二、按传感器结构特征三、按扫描方式四、按分辨率大小五、按输出信号六、按输出色彩接口类型 这张图片对工业相机的分类方式进行了总结,具体如下: 一、按芯片类型 CCD相机:采用电荷耦合器件(CC…...
Oracle查询-in条件超过1000
目录 1.不分页 2.分页 oracle数据库中,in的查询条件超过1000的话,就会报错,应该怎样处理这样的情况呢? 1.不分页 把查询条件分成几个list,每个list有1000个数据,有几个list查询几次数据库就行了 2.分…...
使用rknn进行retinaface部署(C++)
文章目录 RetinaFace导出ONNX导出RKNN编译运行学生课堂开源数据集RetinaFace RetinaFace是一种基于深度学习的高性能人脸检测方法,由InsightFace团队提出。它的核心思想是在单阶段检测器(如RetinaNet)的基础上,结合多任务学习来实现精确的人脸检测和特征点定位。以下是Ret…...
微服务拆分
微服务拆分 接下来,我们就一起将黑马商城这个单体项目拆分为微服务项目,并解决其中出现的各种问题。 熟悉黑马商城 首先,我们需要熟悉黑马商城项目的基本结构: 大家可以直接启动该项目,测试效果。不过,…...
【matlab】matlab知识点及HTTP、TCP通信
1、矩阵运算 点乘:对于两个同维度的向量,点乘结果是这两个向量对应分量的乘积之和。 点除:是指对两个数组的对应元素进行除法运算。 点幂:表示元素对元素的幂运算。 >> A[1,2,3;4,5,6]; B[1,1,1;2,2,2]>> D1B.*AD…...
亿道三防丨三防笔记本是什么意思?和普通笔记本的优势在哪里?
三防笔记本是什么意思?和普通笔记本的优势在哪里? 在现代社会中,笔记本电脑已经成为人们工作和生活中不可或缺的一部分。然而,在一些特殊行业或环境中,普通笔记本电脑由于其脆弱性和对环境条件的敏感性,往…...
C++并发编程之并发可扩展性与阿姆达尔定律
在C并发编程中,可扩展性和阿姆达尔定律(Amdahl’s Law)是两个非常重要的概念,它们帮助我们理解和优化并发程序的性能。下面我们分别讨论这两个概念,并探讨它们在C并发编程中的应用。 可扩展性 可扩展性(S…...
java 迪米特法则,原理、思想、工作流程、实现细节、稳定性、优缺点、应用场景等
迪米特法则(Law of Demeter,LoD),也被称为“最少知识原则”,是一种指导面向对象设计的原则,旨在减少对象之间的耦合度。以下是对迪米特法则的详细解析。 1. 定义 迪米特法则指出:一个对象应该…...
使用 Docker 部署 Java 项目(通俗易懂)
目录 1、下载与配置 Docker 1.1 docker下载(这里使用的是Ubuntu,Centos命令可能有不同) 1.2 配置 Docker 代理对象 2、打包当前 Java 项目 3、进行编写 DockerFile,并将对应文件传输到 Linux 中 3.1 编写 dockerfile 文件 …...
DuckDB:精通Insert语句处理数据冲突
本文介绍DuckDB insert语句用法,包括常规的批量插入,尤其是插入数据冲突的处理,最后还提及returning子句的用法,每个用法提供示例说明。 insert插入数据 INSERT INTO向表中插入新行。可以插入由值表达式指定的一行或多行…...
DFT可测性设置与Tetramax测试笔记
1 DFT 1.1 DFT类型 1、扫描链(SCAN): 扫描路径法是一种针对时序电路芯片的DFT方案.其基本原理是时序电路可以模型化为一个组合电路网络和带触发器(Flip-Flop,简称FF)的时序电路网络的反馈。 Scan 包括两个步骤,scan…...
AttributeError: Unknown IMAP4 command: ‘idle‘
imaplib 原生并不支持 IDLE 命令,这可能导致 AttributeError: Unknown IMAP4 command: idle 错误。解决办法是使用支持 IDLE 命令的库,例如 imapclient,或者通过扩展 imaplib 的方式实现。 以下是两种解决方案: 方法 1࿱…...
css实现响应式详解
一、媒体查询(Media Queries) 基本概念 媒体查询是 CSS3 中用于根据不同的设备特性(如屏幕宽度、高度、设备类型等)应用不同样式规则的技术。它允许你为特定的媒体类型(如屏幕、打印、手持设备等)和条件&a…...
hot100_240. 搜索二维矩阵 II
hot100_240. 搜索二维矩阵 II 直接遍历列减行增 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性: 每行的元素从左到右升序排列。 每列的元素从上到下升序排列。 示例 1: 输入:matrix [[1,4,7,1…...
【网络云SRE运维开发】2025第3周-每日【2025/01/15】小测-【第14章ospf高级配置】理论和实操解析
文章目录 14.1 选择题解题思路和参考答案14.2 理论题解题思路和参考答案14.3 实操题解题思路和参考答案思科(Cisco)设备华为(Huawei)设备小米/锐捷(或其他支持标准CLI命令的设备)通过网络管理工具注意事项 …...
c#-Halcon入门教程——标定
Halcon代码 read_image (NinePointCalibration, D:/Desktop/halcon/ca74d-main/九点标定/NinePointCalibration.gif)rgb1_to_gray (NinePointCalibration, GrayImage)get_image_size (GrayImage, Width, Height) dev_display (GrayImage)* 获取当前显示的窗口句柄 dev_get_win…...
设计和优化用于 AR、HUD 和高级显示系统的表面浮雕光栅
表面浮雕光栅是许多光学系统中的关键组件,在控制增强现实 (AR) 显示器、平视显示器 (HUD) 和其他先进光子器件中的光传播方面发挥着关键作用。作为在这个领域工作的工程师和设计师,您了解针对特定应用优化这…...
编译pytorch——cuda-toolkit-nvcc
链接 https://blog.csdn.net/wjinjie/article/details/108997692https://docs.nvidia.com/cuda/cuda-installation-guide-linux/#switching-between-driver-module-flavorshttps://forums.developer.nvidia.com/t/can-not-load-nvidia-drivers-on-ubuntu-22-10/239750https://…...
Linux 系统资源监控笔记
本文介绍如何在 Linux 系统中查看服务资源剩余情况,包括 CPU、内存、磁盘、网络等资源的监控方法和常用命令。 目录 查看 CPU 和内存使用情况查看磁盘使用情况查看网络使用情况查看服务资源占用查看系统整体资源使用情况图形化工具 1. 查看 CPU 和内存使用情况 使…...
在Linux系统中无网络安装Nginx并配置负载均衡
在Linux系统中无网络安装Nginx并配置负载均衡 在现代的Web开发和运维中,Nginx作为一个高性能的HTTP和反向代理服务器,被广泛应用于负载均衡、静态资源服务、SSL终端等场景。然而,在某些特殊环境下,服务器可能无法访问互联网&…...
Franka例程学习——examples_common
这一次我们学习Franka所有例程里面都要调用的examples_common.h和examples_common.cpp,一个是.h头文件放置声明的函数、类、变量以及宏等内容,.c文件里面是具体的函数实现。 一、源代码 examples_common.h // Copyright (c) 2017 Franka Emika GmbH /…...
浅谈计算机网络02 | SDN控制平面
计算机网络控制平面 一、现代计算机网络控制平面概述1.1 与数据平面、管理平面的关系1.2 控制平面的发展历程 二、控制平面的关键技术剖析2.1 网络层协议2.1.1 OSPF协议2.1.2 BGP协议 2.2 SDN控制平面技术2.2.1 SDN架构与原理2.2.2 OpenFlow协议2.2.3 SDN控制器 一、现代计算机…...
Golang概述
文章目录 1. 什么是程序2. Go语言的诞生小故事2.1 Go 语言的核心开发团队--三个大牛2.2 Google 创造 Golang 的原因2.3 Golang 的发展历程 3. Golang 的语言的特点 1. 什么是程序 程序:就是完成某个功能的指令的集合。画一个图理解: 2. Go语言的诞生小故…...
【STM8S】STM8S之IIC从机
本文最后修改时间:2018年10月30日 18:48 一、本节简介 本文介绍STM8S系列如何使用IIC从机接收来自IIC主机的数据。 二、实验平台 编译软件:IAR for STM8 1.42.2 硬件平台:stm8s003f3p6开发板 仿真器:ST-LINK 库函数版本&…...
SDK调用文心一言如何接入,文心一言API接入教程
一、前期准备 注册百度智能云账号: 前往百度智能云官网注册一个账号。这是接入文心一言API的基础。 了解API接口: 在百度智能云开放平台中,找到文心一言API的详情页,了解提供的API接口类型(如云端API、移动端API、离线…...
实战:FRP内网穿透部署-支持ssh、web访问
目录 1 准备工作2 公网服务器部署server端2.1 frps.ini配置 3 内网客户端部署client端3.1 frpc.ini配置(内网服务器01)3.2 frpc.ini配置(内网服务器02) 4 服务启动脚本4.1 公网服务器 server4.2 内网服务器 client 2 systemctl常见…...
基于Web的宠物医院看诊系统设计与实现(源码+定制+开发)在线预约平台、宠物病历管理、医生诊疗记录、宠物健康数据分析 宠物就诊预约、病历管理与健康分析
博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…...
Pytorch基础教程:从零实现手写数字分类
文章目录 1.Pytorch简介2.理解tensor2.1 一维矩阵2.2 二维矩阵2.3 三维矩阵 3.创建tensor3.1 你可以直接从一个Python列表或NumPy数组创建一个tensor:3.2 创建特定形状的tensor3.3 创建三维tensor3.4 使用随机数填充tensor3.5 指定tensor的数据类型 4.tensor基本运算…...
使用Flink-JDBC将数据同步到Doris
在现代数据分析和处理环境中,数据同步是一个至关重要的环节。Apache Flink和Doris是两个强大的工具,分别用于实时数据处理和大规模并行处理(MPP)SQL数据库。本文将介绍如何使用Flink-JDBC连接器将数据同步到Doris。 一、背景介绍…...
【深度学习】自编码器(Autoencoder, AE)
自编码器(Autoencoder, AE)是一种无监督学习模型,主要用于特征提取、数据降维、去噪和生成模型等任务。它的核心思想是通过将输入压缩到一个低维的潜在空间表示(编码过程),然后再从这个潜在表示重构输入&am…...
跨专业毕业论文写作
跨专业毕业论文写作是一项具有挑战性的任务,但通过合理的规划和方法,你可以顺利完成这篇论文。以下是一些关键步骤和建议,帮助你撰写一篇高质量的跨专业毕业论文。 一、确定研究方向和课题 选择与本科专业相关或感兴趣的研究方向:…...
在 Go语言中一个字段可以包含多种类型的值的设计与接种解决方案
在 Go 中,如果你希望一个字段可以包含多种类型的值,你可以使用以下几种方式来实现: ### 1. **使用空接口 (interface{})** Go 的空接口 interface{} 可以接受任何类型的值,因此,你可以将字段定义为一个空接口&#x…...
为AI聊天工具添加一个知识系统 之32 三“中”全“会”:推理式的ISA(父类)和IOS(母本)以及生成式CMN (双亲委派)之1
本文要点和问题 要点 三“中”全“会”:推理式的ISA的(父类-父类源码)和IOS的(母本-母类脚本)以及生成式 CMN (双亲委派-子类实例)。 数据中台三端架构的中间端(信息系统架构ISA :…...
手撕Transformer -- Day6 -- DecoderBlock
手撕Transformer – Day6 – DecoderBlock 目录 手撕Transformer -- Day6 -- DecoderBlockTransformer 网络结构图DecoderBlock 代码Part1 库函数Part2 实现一个解码器Block,作为一个类Part3 测试 参考 Transformer 网络结构图 Transformer 网络结构 DecoderBlock 代…...
Docker常用命令大全
Docker容器相关命令: 创建并启动容器: docker run:创建一个新的容器并运行一个命令。例如:docker run -d -p 8080:80 nginx这将后台(-d)运行一个Nginx容器,并映射宿主机的8080端口到容器的80端口。 列出容器&#x…...
【Linux探索学习】第二十五弹——动静态库:Linux 中静态库与动态库的详细解析
Linux学习笔记: https://blog.csdn.net/2301_80220607/category_12805278.html?spm1001.2014.3001.5482 前言: 在 Linux 系统中,静态库和动态库是开发中常见的两种库文件类型。它们在编译、链接、内存管理以及程序的性能和可维护性方面有着…...
Vue 实现当前页面刷新的几种方法
以下是 Vue 中实现当前页面刷新的几种方法: 方法一:使用 $router.go(0) 方法 通过Vue Router进行重新导航,可以实现页面的局部刷新,而不丢失全局状态。具体实现方式有两种: 实现代码: <template&g…...
python mysql库的三个库mysqlclient mysql-connector-python pymysql如何选择,他们之间的区别
三者的区别 1. mysqlclient 特点: 是一个用于Python的MySQL数据库驱动程序,用于与MySQL数据库进行交互。 依赖于MySQL的本地库,因此在安装时需要确保系统上已安装了必要的依赖项,如libmysqlclient-dev等。 性能较好,…...
【可持久化线段树】 [SDOI2009] HH的项链 主席树(两种解法)
文章目录 1.题目描述2.思路3.解法一解法一代码 4.解法二解法二代码(版本一)解法二代码(版本二) 1.题目描述 原题:https://www.luogu.com.cn/problem/P1972 [SDOI2009] HH的项链 题目描述 HH 有一串由各种漂亮的贝壳…...