react的闭包陷阱
React 的闭包陷阱是指在使用 React Hooks 时,由于闭包特性导致在某些函数或异步操作中无法正确访问到更新后状态或 prop 的值,而仍旧使用了旧值。下面通过几个代码示例来具体说明闭包陷阱的几种常见情形:
示例 1: useState 闭包陷阱
import { useState } from 'react';function Counter() {const [count, setCount] = useState(0);function handleClick() {setTimeout(() => {console.log('Count inside setTimeout:', count); // 问题:总是显示初始值 0,而非实际点击后的值}, 1000);setCount(count + 1);}return (<div><p>Current Count: {count}</p><button onClick={handleClick}>Increment</button></div>);
}
在这个例子中,handleClick 函数内的 setTimeout 回调形成了一个闭包,它捕获了首次渲染时 count 的值(即 0)。当用户点击按钮触发 handleClick 时,虽然 setCount 更新了状态,但 setTimeout 回调内的 count 仍指向最初捕获的 0,因此在延时一秒后打印出的 count 值不是预期的更新值。
下面是一个关于useState的闭包陷阱
当子组件值变换后给父组件传值,发现传过来的值任然是跟新之前的值,
子:
import React, { useState, useEffect } from "react";const BrotherComponentA = (props) => {const [dataB, setDataB] = useState(0);// useEffect(() => {// props.onSharedDataChange(dataB);// }, [dataB]);const sendDataToBrotherB = () => {setDataB((dataB) => dataB + 1); // 修改兄弟组件的数据props.onSharedDataChange(dataB);};return (<div>{dataB}<button onClick={sendDataToBrotherB}>Send Data to Brother B</button></div>);
};export default BrotherComponentA;父:
import React, { useState } from 'react';
import BrotherComponentA from './Bpp';const ParentComponent = () => {const [sharedData, setSharedData] = useState(null);const handleDataChange = (data) => {console.log("Received data from BrotherComponentA:", data)setSharedData(data);}return (<div><BrotherComponentA onSharedDataChange={handleDataChange} />{sharedData}</div>);
}export default ParentComponent;
解决办法:
useEffect(() => {props.onSharedDataChange(dataB);}, [dataB]);注释:props.onSharedDataChange(dataB);
使用useEffect去依赖收集跟新
示例 2: useEffect 闭包陷阱
import { useState, useEffect } from 'react';function FetchUser() {const [userId, setUserId] = useState(1);const [user, setUser] = useState(null);useEffect(() => {fetch(`https://api.example.com/users/${userId}`).then(response => response.json()).then(data => setUser(data));}, []); // 问题:遗漏了 `userId` 作为依赖function handleUserIdChange(newId) {setUserId(newId);}return (<><input type="number" value={userId} onChange={e => handleUserIdChange(e.target.value)} />{user && <p>User Name: {user.name}</p>}</>);
}
此处 useEffect 用于获取指定 userId 的用户信息。然而,useEffect 的依赖数组为空,意味着它仅在组件挂载时执行一次。当 handleUserIdChange 调用 setUserId 更新 userId 时,useEffect 不会重新执行,因为它没有将 userId 列为依赖。结果,尽管用户输入了新的 ID,fetch 请求仍使用了初始的 userId 值(即 1),导致界面展示的是错误的用户信息。
示例 3: useCallback 闭包陷阱
import { useState, useCallback } from 'react';function FilteredList({ items }) {const [filterText, setFilterText] = useState('');const filteredItems = items.filter(item => item.includes(filterText));const handleFilterChange = useCallback(event => {setFilterText(event.target.value);},[] // 问题:遗漏了 `setFilterText` 作为依赖);return (<div><input type="text" value={filterText} onChange={handleFilterChange} /><ul>{filteredItems.map(item => (<li key={item}>{item}</li>))}</ul></div>);
}
这里 useCallback 用于缓存 handleFilterChange 函数以避免不必要的重渲染。然而,依赖数组为空,意味着 handleFilterChange 在组件整个生命周期内都不会改变。当 setFilterText 被外部因素(如热重载)替换时,handleFilterChange 仍然引用着旧的 setFilterText 实例,导致过滤功能失效。
解决方案
对于上述示例中的闭包陷阱,相应的解决办法如下:
-
示例 1: 使用函数式更新方式,传递一个函数给
setCount:setCount(prevCount => prevCount + 1); -
示例 2: 正确列出
useEffect的依赖:useEffect(() => {// ... }, [userId]); -
示例 3: 将
setFilterText添加到useCallback的依赖列表:const handleFilterChange = useCallback(event => {setFilterText(event.target.value);},[setFilterText] );
通过正确处理闭包和依赖关系,可以避免 React Hooks 中的闭包陷阱,确保状态和副作用逻辑按预期工作。
相关文章:
react的闭包陷阱
React 的闭包陷阱是指在使用 React Hooks 时,由于闭包特性导致在某些函数或异步操作中无法正确访问到更新后状态或 prop 的值,而仍旧使用了旧值。下面通过几个代码示例来具体说明闭包陷阱的几种常见情形: 示例 1: useState 闭包陷阱 import…...
神经网络解决回归问题(更新ing)
神经网络应用于回归问题 优势是什么???生成数据集:通用神经网络拟合函数调整不同参数对比结果初始代码结果调整神经网络结构调整激活函数调整迭代次数增加早停法变量归一化处理正则化系数调整学习率调整 总结ingfnn.py进行计算&am…...
【小红书校招场景题】12306抢票系统
1 坐过高铁吧,有抢过票吗。你说说抢票系统对于后端开发人员而言会有哪些情况? 对于后端开发人员来说,开发和维护一个高铁抢票系统(如中国的12306)会面临一系列的挑战和情况。这些挑战主要涉及系统的性能、稳定性、数据…...
Spring(三)
1. Spring单例Bean是不是线程安全的? Spring单例Bean默认并不是线程安全的。由于多个线程可能访问同一份Bean实例,当Bean的内部包含了可变状态(mutable state)即有可修改的成员变量时,就可能出现线程安全问题。Spring容器不会自动…...
使用element-plus中的表单验证
标签页代码如下: // 注意:el-form中的数据绑定不可以用v-model,要使用:model <el-form ref"ruleFormRef" :rules"rules" :model"userTemp" label-width"80px"><el-row :gutter"20&qu…...
flinksql
Flink SQL 是 Apache Flink 项目中的一个重要组成部分,它允许开发者使用标准的 SQL 语言来处理流数据和批处理数据。Flink SQL 提供了一种声明式的编程范式,使得用户能够以一种简洁、高效且易于理解的方式来表达复杂的数据处理逻辑。 ### 背景 Flink SQL 的设计初衷是为了简…...
Dockerfile中 CMD和ENTRYPOINT的区别
在 Dockerfile 中,CMD 和 ENTRYPOINT 都用于指定容器启动时要执行的命令。它们之间的主要区别是: - CMD 用于定义容器启动时要执行的命令和参数,它设置的值可以被 Dockerfile 中的后续指令覆盖,包括在运行容器时传递的参数。如果…...
【TC3xx芯片】TC3xx芯片的总线内存保护
前言 广义上的内存保护,包括<<【TC3xx芯片】TC3xx芯片MPU介绍>>一文介绍的MPU(常规狭义上的内存保护),<<【TC3xx芯片】TC3xx芯片的Endinit功能详解>>一文中介绍的寄存器的EndInit保护,<<【TC3xx芯片】TC3xx芯片ACCEN寄存器保护详解>>一…...
抖音小店选品必经五个阶段,看你到哪一步了,直接决定店铺爆单率
大家好,我是电商笨笨熊 新手选品必经的阶段就是迷茫期,不知道怎么选品,在哪里选品,选择什么样的品; 而有些玩家也会在进入店铺后疯狂选品,但是上架的商品没有销量; 而这些都是每个玩家都要经…...
ML在骨科手术术前、书中、术后方法应用综述【含数据集】
达芬奇V手术机器人 近年来,人工智能(AI)彻底改变了人们的生活。人工智能早就在外科领域取得了突破性进展。然而,人工智能在骨科中的应用研究尚处于探索阶段。 本文综述了近年来深度学习和机器学习应用于骨科图像检测的最新成果,描述了其贡献、优势和不足。以及未来每项研究…...
vue3-video-play 在安卓上正常播放,在ios上不能播放,问题解决
1.ios上autoplay需要静音,在播放后再打开声音 <vue3videoPlay v-if"!isComponent" v-bind"options" :playsinline"playsinline"></vue3videoPlay>let playsinline computed(() > {if (props.isComponent) {return}o…...
【C++类和对象】上篇
💞💞 前言 hello hello~ ,这里是大耳朵土土垚~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 💥个人主页&#x…...
微信订阅号环境搭建及开发者工具下载
目录 一、注册订阅号 1.1 选择注册 2.2 选择订阅号注册 1.3 登录进入主页面 编辑 1.4 可以进行自定义菜单 1.5 我们重点关注公众平台测试账号 编辑 1.6 自定义一个域名 1.7 用自己的微信扫描这个二维码 编辑 1.8 点击修改,并自定义个域名 二、开发…...
Failed to resolve ‘bss.myhuaweicloud.com‘ ([Errno -2] Name or service not know
Failed to resolve ‘bss.myhuaweicloud.com’ ([Errno -2] Name or service not know 解決方案: 修改/etc/resolv.conf文件来指定DNS服务器,例如添加Google的公共DNS服务器: nameserver 8.8.8.8 nameserver 8.8.4.4...
大厂基础面试题(之二)
Q1:flex布局 Flex布局容器属性包括: flex-direction: 定义主轴的方向,决定flex容器中的子元素的排列方式 flex-wrap:设置子元素是否换行 flex-flow:是flex-direction和flex-wrap的简写形式,用于设置容器的排…...
swiftui macOS实现加载本地html文件
import SwiftUI import WebKitstruct ContentView: View {var body: some View {VStack {Text("测试")HTMLView(htmlFileName: "localfile") // 假设你的本地 HTML 文件名为 index.html.frame(minWidth: 100, minHeight: 100) // 设置 HTMLView 的最小尺寸…...
科技云报道:大模型加持后,数字人“更像人”了吗?
科技云报道原创。 北京冬奥运AI 虚拟人手语主播、杭州亚运会数字人点火、新华社数字记者、数字航天员小诤…当随着越来越多数字人出现在人们生活中,整个数字人行业也朝着多元化且广泛的应用方向发展,快速拓展到不同行业、不同场景。 面向C端࿰…...
轻松驾驭时间流:MYSQL日期与时间函数的实用技巧
🌈 个人主页:danci_🔥 系列专栏:《MYSQL应用》💪🏻 制定明确可量化的目标,坚持默默的做事。 轻松驾驭时间流:MYSQL日期与时间函数的实用技巧 MYSQL日期时间函数是数据库操作中不可…...
如何在极狐GitLab 使用Docker 仓库功能
本文作者:徐晓伟 GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署极狐GitLab。 本文主要讲述了如何在[极狐GitLab…...
streamlit 大模型前段界面
结合 langchain 一起使用的工具,可以显示 web 界面 pip install streamlit duckduckgo-search 运行命令 streamlit run D:\Python_project\NLP\大模型学习\test.py import os from dotenv import load_dotenv from langchain_community.llms import Tongyi load…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...
