​React Hooks 的闭包陷阱问题

这是主包在面试中遇到的一道题目,面试官的问题是:"这个页面初次展示出来时Count和step的值是什么,我点击按钮count和step的值有什么变化?

这个题目主包回答的不好,所以想做一个总结。

题目

import React, { useState, useEffect } from 'react';function useInterval(callback, delay) {useEffect(() => {const id = setInterval(() => {console.log('[Timer Tick]的 count:', callback._countSnapshot);callback();}, delay);return () => clearInterval(id);}, [delay]);
}export default function BuggyCounter() {const [count, setCount] = useState(0);const [step, setStep] = useState(1);function tick() {setCount(count + step);}// 注册定时器useInterval(tick, 1000);return (<div><h1>Count: {count}</h1><div><button onClick={() => setStep((s) => s + 1)}>Increase Step</button><span> 当前 step: {step} </span></div></div>);
}

分析 

首先,先好好阅读代码,主包现在发现主包在面试中有一个致命的问题就是,很多问题还没明白面试官的意思,或者像代码,还没明白代码的意思就已经开始胡说了。往往是越说越远,其实结束面试之后主包再次阅读这段答的稀烂的代码的时候,发现很能看懂。所以不要着急,先明白面试官 的意思在作答。

好的,我们来解析代码,这个函数什么作用呢。首先我们要明白这是自定义了一个Hook。传入两个参数:callback是一个函数,delay动态参数用于设置定时器的。useEffect的部分就是以delay作为依赖,并在return这个处理副作用的部分进行一个清空计时器。它实现的功能是:安全的实行定时器,在组件卸载或 delay 变化时,自动清除之前的定时器。

接下来看tick函数,就是去改变count的状态为count+step;

调用定时器,每1000ms执行一次。
 

好的,现在解析完毕,开始作答。在刚进入页面的时候,我们应该看的到一瞬间的count:0,step:1;但是1000ms后count变为1了。之后如果我们不点击按钮就会保持这样一直不变。

问题

当我们点击按钮之后,只有step的值会增加,而count的值不会增加。

现在我们来解释为什么会这样:

首先,进入页面之后,会因为初态的问题,count和step会保持初态0和1;但是1000ms后,定时器起效了此时tick函数起作用,但是它捕获的是初态的count和step,在定时器循环的过程中,由于闭包问题,count和step一直没有得到更新,所以count不会改变。

控制台呢

你会发现callback函数中根本就没有 _countSnapshot这个属性,所以他是迷惑我们的,一直是undefined。

怎么更改

方案1

setCount((count)=> count + step);

这样就好,我们在每一次更新时,通过回调获取最新的count值。

方案2:将 tick 加入 useInterval 的依赖

修改 useInterval,使其响应 callback 的变化:

function useInterval(callback, delay) {useEffect(() => {const id = setInterval(callback, delay); // 直接使用最新的 callbackreturn () => clearInterval(id);}, [delay, callback]); // 依赖 callback
}

方案3:useRef
 

function useInterval(callback, delay) {const savedCallback = useRef();// 保存最新的回调useEffect(() => {savedCallback.current = callback;}, [callback]);// 设置定时器useEffect(() => {function tick() {savedCallback.current(); // 调用最新的回调}if (delay !== null) {const id = setInterval(tick, delay);return () => clearInterval(id);}}, [delay]);
}

“人间自有真情在 ,宜将寸心报春晖。”

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

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

相关文章

新基建浪潮下:中国新能源汽车充电桩智慧化建设与管理实践

在新基建战略的强力推动下&#xff0c;中国新能源汽车充电桩建设正迎来智慧化升级的重要机遇期。作为连接能源革命与交通革命的关键节点&#xff0c;充电基础设施的智能化转型不仅关乎新能源汽车产业的可持续发展&#xff0c;更是构建新型电力系统的重要支撑。当前&#xff0c;…

如何在多任务环境中设定清晰的项目优先级?

在多任务环境中设定清晰的项目优先级需要明确项目战略价值、紧急性、资源利用效率、风险管理。其中&#xff0c;明确项目战略价值尤为重要&#xff0c;它决定了项目对组织整体战略目标实现的贡献程度。例如&#xff0c;战略价值高的项目&#xff0c;即使不紧急&#xff0c;也应…

【Django】性能优化-普通版

性能优化&#xff1a; 思路 通常无论是什么编程语言或者是什么框架&#xff0c;瓶颈通常都是数据库相关的操作&#xff1b; 大部分的查询慢的问题接口都是频繁查库、全盘扫描、多层for循环嵌套、高频查redis、序列化时多级外键&#xff1b; 多用O(1)查找复杂度的数据 合理使…

数据治理域——离线数据开发

摘要 文本主要介绍了离线数据开发相关内容,包括业务与流程、阿里MaxCompute系统设计以及阿里调度系统设计。离线数据开发是大数据开发核心组成部分,用于处理批量数据,支持企业多种需求,其流程涵盖需求调研、数据源接入等环节。阿里MaxCompute系统架构与特点被阐述,调度系…

python-docx 库教程

Python-docx 库介绍 官网文档 python-docx 是一个用于创建和修改 Microsoft Word (.docx) 文件的 Python 库。它允许你通过编程方式生成格式化的文档&#xff0c;添加文本、段落、表格、图片等元素&#xff0c;而无需依赖 Microsoft Word 应用程序。 主要功能 创建新的 Word…

Ansible小试牛刀

注意事项 除了安装的zabbix相关组件 使用此脚本安装的所有软件版本均为系统默认版本 安装软件 zabbix相关组件&#xff0c;包括server&#xff0c;agent等 MySQL Redis NGINX openjdk maven nodejs keepalived iptables ipvsadm 使用剧本 --- - hosts: allname…

MCP使用

什么是MCP Model Context Protocol (MCP) 是由 Anthropic 公司于 2024 年 11 月推出的一种开放协议标准&#xff0c;目的在于标准化LLM 与外部数据源、工具及服务之间的交互方式。MCP 被广泛类比为“AI 领域的 USB-C 接口” MCP与Function Calling的区别 MCP 的核心概念 1.…

边缘计算一:现代前端架构演进图谱 —— 从 SPA 到边缘渲染

过去十年&#xff0c;前端项目架构经历了从简单 HTML 文件到复杂框架的飞跃&#xff0c;但很多开发者忽略了**“渲染位置”与“资源交付方式”**对体验与性能的根本性影响。 从最初的浏览器渲染&#xff0c;到现在“在离用户最近的地方动态返回 HTML”&#xff0c;架构正在悄悄…

linux学习记录(六)三个常用命令介绍

1.vim命令 Vim是由Vi发展过来的文本编译器&#xff0c;其代码补全、编译及错误跳转等方便编程的功能特别丰富&#xff0c;在程序员中被广泛使用。 1.1 语法 vim filename 1.2 vi/vim的使用 vi/vim 共分为三种模式&#xff0c;命令模式&#xff08;Command Mode&#xff09;、…

用Python获取京东关键字接口的用户指南

在电商数据分析和市场研究中&#xff0c;获取京东平台的关键字搜索结果数据具有重要意义。本文将详细介绍如何使用Python调用京东开放平台的API接口&#xff0c;获取关键字相关的商品数据&#xff0c;并进行解析和处理。 一、准备工作 &#xff08;一&#xff09;注册京东开发…

观测云,全球领先的监控观测平台亮相亚马逊云科技中国峰会!

观测云每年都不会缺席亚马逊云科技峰会 忙完一整季的产品发布&#xff0c;我们终于将目光投向这场全球顶尖的云技术盛会——2025亚马逊云科技中国峰会。如果你也在这个领域&#xff0c;应该已经感觉到了&#xff1a;这不只是一场大会&#xff0c;而是一个信号。AI、可观测性、…

消息队列处理模式:流式与批处理的艺术

&#x1f30a; 消息队列处理模式&#xff1a;流式与批处理的艺术 &#x1f4cc; 深入解析现代分布式系统中的数据处理范式 一、流式处理&#xff1a;实时数据的"活水" 在大数据时代&#xff0c;流式处理已成为实时分析的核心技术。它将数据视为无限的流&#xff0c;…

一起学习swin-transformer(一)

Transform学习链接 从零开始设计Transformer模型&#xff08;1/2&#xff09;——剥离RNN&#xff0c;保留Attention-CSDN博客 Transformer-PyTorch实战项目——文本分类_transformer文本分类 pytorch-CSDN博客 从零开始设计Transformer模型&#xff08;2/2&#xff09;——…

PyQt常用控件的使用:QFileDialog、QMessageBox、QTreeWidget、QRadioButton等

文章目录 一、控件常用函数介绍二、QFileDialog&#xff08;文件类操作&#xff09;三、QMessageBox(对话框)四、QTreeWidget&#xff08;树结构类操作&#xff09;4.1 树结构的初始化4.2 递归读取完整树结构4.3 两QTreeWidget滑轮同步滑动4.4 信号槽绑定 五、QCombox改写下拉多…

校园导航系统核心技术解析:高精度定位与 AR 实景导航的应用实践

本文面向校园信息化建设者、技术开发者及教育行业数字化转型关注者&#xff0c;旨在解析如何通过 “高精度定位 AR/VR 场景化服务” 技术体系&#xff0c;破解校区因建筑复杂、人流密集导致的寻路效率低下问题&#xff0c;探讨如何利用现有技术解决校园内导航难题&#xff0c;…

java大文件分段下载

后端代码 package com.jy.jy.controller;import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.a…

antd-vue - - - - - a-table排序

antd-vue - - - - - a-table排序 1. 重点代码:2. 代码示例&#xff1a;3. 进阶版写法 1. 重点代码: sorter: {compare: (a, b) > a.columnsKeys - b.columnsKeys,multiple: 1, },解析&#xff1a; compare: 自定义排序函数&#xff0c;用于比较两个对象。 multiple: 排序优…

【AI】模型vs算法(以自动驾驶为例)

模型vs算法&#xff08;以自动驾驶为例&#xff09; 一、自动驾驶的核心任务二、以自动驾驶为例&#xff0c;模型vs算法的实际分工1. 感知环节&#xff1a;“看懂”周围环境&#xff08;如识别行人、车道线、车辆&#xff09;2. 预测环节&#xff1a;“预判”其他交通参与者的行…

机器学习与深度学习19-线性代数02

目录 前文回顾6.协方差矩阵与主成分分析7.矩阵的奇异值分解8.神经网络的前向传播和反向传播9.矩阵的迹10.特征工程的多项式特征扩展 前文回顾 上一篇文章链接&#xff1a;地址 6.协方差矩阵与主成分分析 协方差矩阵是一个对称矩阵&#xff0c;用于衡量随机变量之间的线性相关…

青藏高原ASTER_GDEM数据集(2011)

共享方式&#xff1a;开放获取数据大小&#xff1a;73.69 GB数据时间范围&#xff1a;2012-04-08 — 2012-05-08元数据更新时间&#xff1a;2021-10-15 数据集摘要 ASTER Global Digital Elevation Model &#xff08;ASTER GDEM&#xff09;是美国航空航天局 &#xff08;NAS…