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

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 时&#xff0c;由于闭包特性导致在某些函数或异步操作中无法正确访问到更新后状态或 prop 的值&#xff0c;而仍旧使用了旧值。下面通过几个代码示例来具体说明闭包陷阱的几种常见情形&#xff1a; 示例 1: useState 闭包陷阱 import…...

神经网络解决回归问题(更新ing)

神经网络应用于回归问题 优势是什么&#xff1f;&#xff1f;&#xff1f;生成数据集&#xff1a;通用神经网络拟合函数调整不同参数对比结果初始代码结果调整神经网络结构调整激活函数调整迭代次数增加早停法变量归一化处理正则化系数调整学习率调整 总结ingfnn.py进行计算&am…...

【小红书校招场景题】12306抢票系统

1 坐过高铁吧&#xff0c;有抢过票吗。你说说抢票系统对于后端开发人员而言会有哪些情况&#xff1f; 对于后端开发人员来说&#xff0c;开发和维护一个高铁抢票系统&#xff08;如中国的12306&#xff09;会面临一系列的挑战和情况。这些挑战主要涉及系统的性能、稳定性、数据…...

Spring(三)

1. Spring单例Bean是不是线程安全的? Spring单例Bean默认并不是线程安全的。由于多个线程可能访问同一份Bean实例&#xff0c;当Bean的内部包含了可变状态&#xff08;mutable state&#xff09;即有可修改的成员变量时&#xff0c;就可能出现线程安全问题。Spring容器不会自动…...

使用element-plus中的表单验证

标签页代码如下&#xff1a; // 注意&#xff1a;el-form中的数据绑定不可以用v-model&#xff0c;要使用: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 中&#xff0c;CMD 和 ENTRYPOINT 都用于指定容器启动时要执行的命令。它们之间的主要区别是&#xff1a; - CMD 用于定义容器启动时要执行的命令和参数&#xff0c;它设置的值可以被 Dockerfile 中的后续指令覆盖&#xff0c;包括在运行容器时传递的参数。如果…...

【TC3xx芯片】TC3xx芯片的总线内存保护

前言 广义上的内存保护,包括<<【TC3xx芯片】TC3xx芯片MPU介绍>>一文介绍的MPU(常规狭义上的内存保护),<<【TC3xx芯片】TC3xx芯片的Endinit功能详解>>一文中介绍的寄存器的EndInit保护,<<【TC3xx芯片】TC3xx芯片ACCEN寄存器保护详解>>一…...

抖音小店选品必经五个阶段,看你到哪一步了,直接决定店铺爆单率

大家好&#xff0c;我是电商笨笨熊 新手选品必经的阶段就是迷茫期&#xff0c;不知道怎么选品&#xff0c;在哪里选品&#xff0c;选择什么样的品&#xff1b; 而有些玩家也会在进入店铺后疯狂选品&#xff0c;但是上架的商品没有销量&#xff1b; 而这些都是每个玩家都要经…...

ML在骨科手术术前、书中、术后方法应用综述【含数据集】

达芬奇V手术机器人 近年来,人工智能(AI)彻底改变了人们的生活。人工智能早就在外科领域取得了突破性进展。然而,人工智能在骨科中的应用研究尚处于探索阶段。 本文综述了近年来深度学习和机器学习应用于骨科图像检测的最新成果,描述了其贡献、优势和不足。以及未来每项研究…...

vue3-video-play 在安卓上正常播放,在ios上不能播放,问题解决

1.ios上autoplay需要静音&#xff0c;在播放后再打开声音 <vue3videoPlay v-if"!isComponent" v-bind"options" :playsinline"playsinline"></vue3videoPlay>let playsinline computed(() > {if (props.isComponent) {return}o…...

【C++类和对象】上篇

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…...

微信订阅号环境搭建及开发者工具下载

目录 一、注册订阅号 1.1 选择注册 2.2 选择订阅号注册 1.3 登录进入主页面 ​编辑 1.4 可以进行自定义菜单 1.5 我们重点关注公众平台测试账号 ​编辑 1.6 自定义一个域名 1.7 用自己的微信扫描这个二维码 ​编辑 1.8 点击修改&#xff0c;并自定义个域名 二、开发…...

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 解決方案&#xff1a; 修改/etc/resolv.conf文件来指定DNS服务器&#xff0c;例如添加Google的公共DNS服务器&#xff1a; nameserver 8.8.8.8 nameserver 8.8.4.4...

大厂基础面试题(之二)

Q1&#xff1a;flex布局 Flex布局容器属性包括&#xff1a; flex-direction: 定义主轴的方向&#xff0c;决定flex容器中的子元素的排列方式 flex-wrap&#xff1a;设置子元素是否换行 flex-flow&#xff1a;是flex-direction和flex-wrap的简写形式&#xff0c;用于设置容器的排…...

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 虚拟人手语主播、杭州亚运会数字人点火、新华社数字记者、数字航天员小诤…当随着越来越多数字人出现在人们生活中&#xff0c;整个数字人行业也朝着多元化且广泛的应用方向发展&#xff0c;快速拓展到不同行业、不同场景。 面向C端&#xff0…...

轻松驾驭时间流:MYSQL日期与时间函数的实用技巧

​&#x1f308; 个人主页&#xff1a;danci_&#x1f525; 系列专栏&#xff1a;《MYSQL应用》&#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 轻松驾驭时间流&#xff1a;MYSQL日期与时间函数的实用技巧 MYSQL日期时间函数是数据库操作中不可…...

如何在极狐GitLab 使用Docker 仓库功能

本文作者&#xff1a;徐晓伟 GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 本文主要讲述了如何在[极狐GitLab…...

streamlit 大模型前段界面

结合 langchain 一起使用的工具&#xff0c;可以显示 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…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...

OD 算法题 B卷【正整数到Excel编号之间的转换】

文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的&#xff1a;a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...

消息队列系统设计与实践全解析

文章目录 &#x1f680; 消息队列系统设计与实践全解析&#x1f50d; 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡&#x1f4a1; 权衡决策框架 1.3 运维复杂度评估&#x1f527; 运维成本降低策略 &#x1f3d7;️ 二、典型架构设计2.1 分布式事务最终一致…...