React hooks的闭包陷阱

react hooks 陷阱

  • hooks必须放在函数顶层, 不能在条件分支和方法内

1、useState陷阱

异步陷阱

function Index() {const [count, setCount] = useState(0)function add(){setCount( count + 1 )console.log(count);  // 0}return (<div><span>{count}</span><button @click=()=>{ add() }> + </button></div>)
}

点击一次按钮,发现页面是更新了,但是console还是上一次的值

【解决方法】:

  • 所以我们不能修改后,把值去拿去其他操作 (应该拿 count+1)
  • 可以通过 promise 来 .then 获取 最新 👇
function Index() {const [count, setCount] = useState(0)function add(){new Promise((resolve) => {setCount((count) => {resolve(count + 1)return count + 1})}).then((res) => {// 下一步操作console.log(res)})}return (<div><span>{count}</span><button onClick={add}> ++ </button></div>)
}

合并陷阱,只执行最后一个

function Index() {const [count, setCount] = useState(0)function add(){setCount( count + 1 )setCount( count + 2 )setCount( count + 3 ) // 只执行这个}return (<div><span>{count}</span><button onClick={add}> ++ </button></div>)
}

此时 只执行了 最后一个 setCount , 导致数据部分逻辑未执行
如果出现这种 判断条件多次 操作 useState 怎么解决 👇

function add(){let num = count;if(...) { num += 1; }if(...) { num += 2; }if(...) { num += 3; }setCount( num );}

那就不写多个setCount

再看个例子:

function Index() {const [count, setCount] = useState(100);function add(){// 合并setCount( count + 1 )setCount( count + 1 )console.log(1, count) // 100// 传入函数,不会合并setCount( count => count + 1 )setCount( count => count + 3 )console.log(2, count) // 100// 点击一次后 count显示为105}return (<div><span>{count}</span> <button onClick={() => add() } > + </button></div>)
}

2、useEffect 陷阱

过期闭包

function Index() {const [count, setCount] = useState(0)useEffect(()=>{setInterval(() => {   console.log(`Count: ${count}`)  }, 1000)}, [])return (<div><span>{count}</span><button onClick=()=>{ setCount(count+1) }> + </button></div>)
}

默认就会运行 每隔1s打印0
点击按钮,count有更新,但是console一直是0
说明此时的 useEffect 中的 count ,还是取的 过期的值

react特点,每次更新都会重新执行这个函数,每次就+1, 是另外一个函数了,不是原来这个函数
但是setInterval的count永远是第一个函数里面的,形成了闭包

【解决方法】:
需要,添加依赖项 count ,
并且每次更新,添加计时器,结束改变计时器

function Index() {const [count, setCount] = useState(0);useEffect(()=>{const time = setInterval(() => {   console.log(`Count: ${count}`)  }, 1000)return () => { clearInterval(time) } // 关键  清除上一次的setInterval }, [count])return (<div><span>{count}</span><button @click=()=>{ setCount(count+1) }> + </button></div>)
}

3、useCallback 陷阱

useCallback 本来拿来优化性能,当依赖变化不用重新注册该函数
使用不当 也会出现一定的问题

获取父组件的值,不是最新

function Parent() {let [count, setCount] = useState(0);return (<div><button onClick={() => setCount(count+1)}> +1 </button>// 子组件<Child count={count} /></div>)
}function Child(props){let log = useCallback(() => {  console.log(props.count)  }, [])return (<div>count: {props.count}<button onClick={() => log()}> 打印 </button></div>)
}

此时我们在 父组件点击 增加按钮
子组件的 count 发生改变 ,我们在点击打印按钮,发现count 一直是0
说明useCallback 依赖为【】数组,取到count 已经过期了

【解决方法】
方法1 :等于没有优化 (依赖更新,useCallback重写一次)

  let log = useCallback(() => {  console.log(props.count)  }, [props.count])

方法2 :将获取 count 的方法 创建到父组件,子组件调用父组件方法

function Parent() {let [count, setCount] = useState(0);let log = useCallback(() => {  console.log(count)  }, [])return (<div><button onClick={() => setCount(count+1)}> +1 </button>// 子组件<Child count={count} log={log} /></div>)
}function Child(props){return (<div>count: {props.count}<button onClick={() => props.log()}> 打印 </button></div>)
}

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

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

相关文章

浅谈中国汽车充电桩行业市场状况及充电桩选型的介绍

安科瑞虞佳豪 车桩比降低是完善新能源汽车行业配套的一大重要趋势&#xff0c;目前各国政府都在努力推进政策&#xff0c;通过税收减免、建设补贴等措施提升充电桩建设速度&#xff0c;以满足新能源汽车需求。 近年来&#xff0c;在需求和技术的驱动下&#xff0c;充电桩的平…

Mac怎么删除文件和软件?苹果电脑删除第三方软件方法

Mac删除程序这个话题为什么一直重复说或者太多人讨论呢&#xff1f;因为如果操作不当&#xff0c;可能会导致某些不好的影响。因为Mac电脑如果有太多无用的应用程序&#xff0c;很有可能会拖垮Mac系统的运行速度。或者如果因为删除不干净&#xff0c;导致残留文件积累在Mac电脑…

Jmeter的接口自动化测试

在去年实施了一年的三端&#xff08;PC、无线M站、无线APP【Android、IOS】&#xff09;后&#xff0c;今年7月份开始&#xff0c;我们开始进行接口自动化的实施&#xff0c;目前已完成了整个框架的搭建以及接口的持续测试集成。今天做个简单的分享。 在开始自动化投入前&#…

第14期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练 Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大型语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以…

vscode 保存 “index.tsx“失败: 权限不足。选择 “以超级用户身份重试“ 以超级用户身份重试。

vscode 保存 "index.tsx"失败: 权限不足。选择 “以超级用户身份重试” 以超级用户身份重试。 操作&#xff1a;mac在文件夹中创建文件&#xff0c;sudo 创建umiJs项目 解决&#xff1a;修改文件夹权限 右键文件夹

STM32F103单片机内部RTC实时时钟驱动程序

一、STM32f103系列RTC功能 RTC实时时钟功能是嵌入式软件开发中比较常用的功能&#xff0c;一般MCU的RTC功能都带有年月日时间寄存器&#xff0c;比如STM32F4xx系列&#xff0c;RTC描述如下&#xff1a; 可见F4系列的RTC功能比较强大&#xff0c;设置好初始时间后&#xff0c;读…

NodeJS爬取墨刀上的设计图片

背景 设计人员分享了一个墨刀的原型图&#xff0c;但是给的是只读权限&#xff0c;无法下载其中的素材&#xff1b;开发时想下载里面的一张动图&#xff0c;通过浏览器的F12工具在页面结构找到了图片地址。 但是浏览器直接访问后发现没权限&#xff1a; Nginx 的 403 页面。。…

批量编辑 Outlook 联系人

现状 Outlook 自带的联系人编辑功能无法快速、批量编辑联系人字段使用 Excel 等外部编辑器&#xff0c;可批量编辑联系人 导出联系人到文件 在【联系人】界面&#xff0c;点击【文件】在【文件】界面&#xff0c;点击【打开和导出】–>【导入/导出】在弹出的向导窗口中点…

语法复习之C语言与指针

内存是如何存储数据的&#xff1f; 在C语言中定义一个变量后&#xff0c;系统就会为其分配内存空间。这个内存空间包括了地址和长度。将变量赋值后&#xff0c;该值就被写入到了指定的内存空间中。内存空间的大小一般以字节作为基本单位。   普通变量存放的是数据&#xff0c…

学习paddle-detection(paddlex的使用)

首先下载paddlex&#xff08;网页&#xff09;的本地软件&#xff0c;下载链接如下&#xff1a; paddlex 下载完成后进行安装 打开后选择开发者模式&#xff0c;开发者模式主要是和VScode进行集成 本章节主要介绍在开发者模式下可以查看和编辑的文件及其作用&#xff0c;关于…

【优选算法系列】第一节.双指针(283. 移动零和1089. 复写零)

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;优选算法系列 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01;&#xff01…

LabVIEW开发基于图像处理的车牌检测系统

LabVIEW开发基于图像处理的车牌检测系统 自动车牌识别的一般步骤是图像采集、去除噪声的预处理、车牌定位、字符分割和字符识别。结果主要取决于所采集图像的质量。在不同照明条件下获得的图像具有不同的结果。在要使用的预处理技术中&#xff0c;必须将彩色图像转换为灰度&am…

LaTeX:在标题section中添加脚注footnote

命令讲解 先导包&#xff1a; \usepackage{footmisc} 设原标题为&#xff1a; \section{标题内容} 更改为&#xff1a; \section[标题内容]{标题内容\protect\footnote{脚注内容}} 语法讲解&#xff1a; \section[]{} []内为短标题&#xff0c;作为目录和页眉中的标题。…

在Golang中理解错误处理

处理Golang中临时错误和最终错误的策略和示例 作为一名精通Golang的开发人员&#xff0c;您了解有效的错误处理是编写健壮可靠软件的关键因素。在复杂系统中&#xff0c;错误可能采取各种形式&#xff0c;包括临时故障和最终失败。在本文中&#xff0c;我们将探讨处理Golang中…

【java】建筑施工一体化智慧工地信息管理系统源码

智慧工地系统是一种利用人工智能和物联网技术来监测和管理建筑工地的系统。它可以通过感知设备、数据处理和分析、智能控制等技术手段&#xff0c;实现对工地施工、设备状态、人员安全等方面的实时监控和管理。 一、智慧工地让工程施工智能化 1、内容全面&#xff0c;多维度数…

8086汇编环境的使用

先打开emu8086&#xff0c;写入代码 ;给11003H的地址赋1234H的值;不能直接给DS赋值需要寄存器中转 mov dx, 1100H mov ds, dx mov ax, 1234H ;不能直接给内存地址赋值&#xff0c;需要DS:[偏移地址]指向内存 mov [3H], ax 点击emulate开始模拟 出现调试框&#xff0c;调试框的…

IDEA部署SSM项目mysql数据库MAVEN项目部署教程

如果 SSM 项目是基于 Maven 构建的&#xff0c;则需要配置 maven 环境&#xff0c;否则跳过这一步 步骤一&#xff1a;配置 Maven 第一步&#xff1a;用 IDEA 打开项目&#xff0c;准备配置 maven 环境 &#xff0c;当然如果本地没有提前配置好 maven&#xff0c;就用 IDEA 默…

25-什么是事件循环

一、是什么 &#x1f37f;&#x1f37f;&#x1f37f;JavaScript是一门单线程的语言、 意味着同一时间内只能做一件事&#xff0c;但是这并不意味着单线程就是阻塞&#xff0c;而实现单线程非阻塞的方法就是事件循环 在JavaScript中&#xff0c;所有的任务都可以分为 同步任…

【Docker】Docker Compose服务依赖与健康检查

docker compose环境变量 为增加安全性&#xff0c;在前面的python例子中增加redis的密码校验&#xff0c;密码从环境变量中获取&#xff1a; from flask import Flask from redis import StrictRedis import os import socketapp Flask(__name__) redis StrictRedis(hostos…

操作系统——内存扩容:覆盖技术、交换技术(王道视频p44)

1.对于覆盖技术 和 交换技术&#xff1a;&#xff08;并不是重点&#xff09;