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

使用useCallback引发对闭包的理解

一、先简单介绍一下闭包:

闭包是 JavaScript 中的重要概念,它指的是一个函数可以“记住”并访问其词法作用域,即使在这个函数的外部被执行。简单来说,闭包是由函数及其相关的环境组合而成的。

闭包的特性

函数内部可以访问外部变量:

  • 闭包允许一个函数访问其外部作用域中的变量,即使这个函数在外部被调用。

保持状态:

  • 闭包可以用来保持状态,因为它可以“记住”外部变量的值。

私有变量:

  • 通过闭包,可以创建私有变量,这些变量不能被外部代码直接访问,只能通过闭包内部的函数进行访问和修改。

简单示例:

匿名函数持久化存储了外部count的值(保持状态)

function createCounter() {let count = 0; // count 是一个私有变量return function() {count += 1; // 访问外部变量 countreturn count; // 返回当前的 count 值};
}const counter = createCounter();console.log(counter()); // 输出 1
console.log(counter()); // 输出 2
console.log(counter()); // 输出 3

二、在React中使用useState产生闭包:

import React, { useState } from 'react';const Counter = () => {const [count, setCount] = useState(0);const increment = () => {setCount(count + 1); // 这里使用了捕获的 count 值setCount(count + 1); // 这次仍然使用的是同样的捕获值};return (<div><p>Count: {count}</p><button onClick={increment}>Increment</button></div>);
};export default Counter;

当你点击按钮时,increment 函数会调用 setCount 两次,但由于 count 是在函数创建时捕获的值,这导致 count 只增加 1,而不是 2。(内部访问外部变量,由于内部两次访问的count的值是一样的,所以无论调用多少次,这只导致count只能增加一次)

 解决方法:函数式的更新

所以为了避免这个问题,React采用函数形式的更新方式,以此来访问最新的状态值:

import React, { useState } from 'react';const Counter = () => {const [count, setCount] = useState(0);const increment = () => {setCount(count + 1); // 这里使用了捕获的 count 值setCount(count + 1); // 这次仍然使用的是同样的捕获值};return (<div><p>Count: {count}</p><button onClick={increment}>Increment</button></div>);
};export default Counter;

三、 useCallback的依赖项:

创建一个外部的useState:

const [todoList, setTodoList] = useState([]);

为什么要添加todolist的依赖项?

使用了依赖项:

const openCheckModal = useCallback((id) => {setCurrentData(() => todoList.filter(item => item.id === id));setShowCheckModal(true);
}, [todoList]);

 查看定义:

useCallback缓存函数:

它确保只有在依赖项变化时才重新创建函数,从而避免子组件不必要的重新渲染。

解释:

由于闭包的问题,内部使用了外部变量(todolist),当外部变量更新的时候需要更新到最新的状态,换句话说,在初始化的时候 const openCheckModal 这个变量只加载了一次,由于闭包的问题,todolist存储的一直是初始化的todolist,当todolist改变的时候,此时也应该去动态更新当前这个const 变量

这样不会导致闭包的出现,也可以使得内部引用到的是外部最新的数据

在下面的例子中也使用了todolist,为什么只有第一个要添加todolist的依赖项呢?

 不使用依赖项

const addItem = useCallback((value) => {const dataItem = {id: new Date().getTime(),content: value,completed: false};setTodoList((todoList) => [...todoList, dataItem]);setInputShow(false);
}, []);

由于todolist形参传递,引用来自useState定义的变量,无关与addItem这个变量,也不会产生闭包,所以不需要传递todolist依赖项

总结:

当你将外部变量放入依赖数组中时,有几个要点需要理解:

  • 保持一致性: 如果在回调函数内部使用了某个外部变量(例如 props 或 state),将这个变量放入依赖数组中可以确保你使用的是最新的值。这避免了闭包问题,即在回调函数中引用的变量是旧值。
  • 不必要的重新调用: 如果依赖数组中的变量发生变化,但回调函数并没有被调用(例如,函数没有被某个事件触发),那么不会造成逻辑错误。只有在实际调用这个回调函数时,内部逻辑会基于最新的依赖值执行。

要想使用最新的值,就需要动态更新当前useCallback,添加外部变量的依赖项,以便获取最新的数据

相关文章:

使用useCallback引发对闭包的理解

一、先简单介绍一下闭包: 闭包是 JavaScript 中的重要概念&#xff0c;它指的是一个函数可以“记住”并访问其词法作用域&#xff0c;即使在这个函数的外部被执行。简单来说&#xff0c;闭包是由函数及其相关的环境组合而成的。 闭包的特性 函数内部可以访问外部变量: 闭包…...

gvim添加至右键、永久修改配置、放大缩小快捷键、ctrl + c ctrl +v 直接复制粘贴、右键和还原以前版本(V)冲突

一、将 vim 添加至右键 进入安装目录找到 vim91\install.exe 管理员权限执行 Install will do for you:1 Install .bat files to use Vim at the command line:2 Overwrite C:\Windows\vim.bat3 Overwrite C:\Windows\gvim.bat4 Overwrite C:\Windows\evim.bat…...

腾讯云-COS

COS 对象存储 是一种可扩展的云端数据存储服务。它适用于存储任意类型的文件&#xff0c;并且可以针对这些文件进行访问控制。 CORS 跨域资源共享 是一种机制&#xff0c;它使用额外的HTTP头来告诉浏览器允许一个域上的Web应用请求另一个域上的资源。当需要从一个域名下的网页向…...

蓝桥杯每日真题 - 第16天

题目&#xff1a;&#xff08;卡牌&#xff09; 题目描述&#xff08;13届 C&C B组C题&#xff09; 解题思路&#xff1a; 题目分析&#xff1a; 有 n 种卡牌&#xff0c;每种卡牌的现有数量为 a[i]&#xff0c;所需的最大数量为 b[i]&#xff0c;还有 m 张空白卡牌。 每…...

基因组之全局互作热图可视化

引言 PlotHiC 是一个专为 Hi-C 数据可视化分析而设计的 Python 包。Hi-C 技术是一种能够检测染色体三维结构的实验方法&#xff0c;它能揭示 DNA 在细胞核内的三维组织结构。为了更好地展示和解释这些复杂的数据&#xff0c;PlotHiC[1] 可以帮助用户方便地绘制Hi-C 数据的热图。…...

基于Lora通讯加STM32空气质量检测WIFI通讯

目录 目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 1.电路图采用Altium Designer进行设计&#xff1a; 2.实物展示图片 三、程序源代码设计 四、获取资料内容 前言 随着环境污染问题的日益严重&#xff0c;空气质量的监测与管理已经…...

STM32 极速入门第一天基础拓展 驱动i2c屏幕 ( 使用PlatformIO开发STM32单片机 )

输入输出模式解析 输出模式 在输出模式下&#xff0c;通常不需要设置上下拉电阻. 输出电平由 LL_GPIO_SetOutputPin 和 LL_GPIO_ResetOutputPin 函数直 接控制。 输入模式 在输入模式下&#xff0c;设置上下拉电阻是非常重要的. 输入引脚悬空时可能会导致不确定的电平&#xf…...

【WPF】Prism学习(五)

Prism Commands 1.错误处理&#xff08;Error Handling&#xff09; Prism 9 为所有的命令&#xff08;包含AsyncDelegateCommand&#xff09;提供了更好的错误处理。 避免用try/catch包装每一个方法根据不同遇到的异常类型来提供特定的逻辑处理可以在多个命令之间共享错误处…...

RabbitMQ的基本概念和入门

RabbitMQ 的基本概念和入门 RabbitMQ 是一款流行的开源消息队列中间件&#xff0c;实现了高级消息队列协议&#xff08;AMQP&#xff09;。它使用Erlang语言编写&#xff0c;具备高可用性、可扩展性和易用性等特点&#xff0c;广泛应用于各种分布式系统中。本文将详细介绍Rabb…...

Shell脚本6 -- 条件判断if

声明&#xff1a; 本文的学习内容来源于B站up主“泷羽sec”视频【shell编程&#xff08;4&#xff09;脚本与用户交互以及if条件判断】的公开分享&#xff0c;所有内容仅限于网络安全技术的交流学习&#xff0c;不涉及任何侵犯版权或其他侵权意图。如有任何侵权问题&#xff0c…...

经验笔记:从生成 SSH 密钥到成功连接测试(以Gitee为例)

从生成 SSH 密钥到成功连接测试的经验笔记&#xff08;以Gitee为例&#xff09; 1. 生成 SSH 密钥对 选择合适的加密算法 ED25519&#xff1a; 密钥长度&#xff1a;私钥 256 位&#xff08;32 字节&#xff09;&#xff0c;公钥 256 位&#xff08;32 字节&#xff09;&#…...

Object.defineProperty和响应式

Object.defineProperty()是一个监听对象属性变化的方法。一般情况下我们是不会直接使用的&#xff0c;或者说我们遇到的场景还没有这么高级。 最有名的例子就是Vue2的响应式实现&#xff0c;就是通过这个方法来实现的。 用起来不难&#xff0c;就是个API&#xff0c;只是用的…...

前端web

题目&#xff1a;制作带有下拉悬停菜单的导航栏 效果图 一、先制作菜单栏 <body> <div id"menu"> <div id"container"> <div class"item">游戏1 <div cla…...

DDNet 服务器配置教程 Linux 环境

DDNet 服务器配置教程 Linux 环境 配置之前可以参考一下官方网址给出的内容 官方网址&#xff1a;DDNet官方 环境说明 OS: Debian 11 安装 可以直接从官网下载&#xff0c;也可以使用这个链接: Linux_DDNet 下载链接 上文中给的链接会因为更新而出现版本落后的情况&#x…...

Vue 2 —监视器实现动态切换表单属性值

目录 一、需求背景 二、监视器语法 三、实例展示 1、HTML部分 2、JS部分 四、使用场景总结 1. 表单验证 2. 动态更新 UI 3. 数据同步 4. 计算属性的替代方案 计算属性的优势 : 简洁性&#xff1a; 监视器的优势 : 灵活性&#xff1a; 多属性依赖&#xff1a; 副…...

Qt_day10_程序打包(完结)

目录 1. 设置图标 2. Debug和Release版本 3. 动态链接库 4. 打包 5. 联系项目要求 Qt开发的程序最终都是要给用户使用的&#xff0c;用户的电脑上不可能装一个Qt的开发环境导入项目使用。因此项目项目开发完成后需要打包——制作成安装包&#xff0c;用户直接下载并安装即可使用…...

golang通用后台管理系统09(系统操作日志记录)

1.日志工具类 package log/**** 日志记录 wangwei 2024-11-18 15:30*/ import ("log""os""path/filepath""time" )// 获取以当前日期命名的日志文件路径 func getLogFilePath() string {currentDate : time.Now().Format("2006-…...

如何确保爬取的数据准确性和完整性?

在数据驱动的业务环境中&#xff0c;爬虫程序的准确性和完整性至关重要。本文将探讨如何使用Java编写爬虫程序&#xff0c;并确保其在爬取数据时的准确性和完整性。 1. 精确的HTML解析 确保数据准确性的第一步是精确地解析HTML。Jsoup是Java中常用的HTML解析库&#xff0c;它提…...

【java】JDK安装

Java Downloads | Oracle 中国 next 注意安装的路径 环境变量...

科技改变工作方式:群晖NAS安装内网穿透实现个性化办公office文档分享(1)

文章目录 前言1. 本地环境配置2. 制作本地分享链接3. 制作公网访问链接4. 公网ip地址访问您的分享相册5. 制作固定公网访问链接 前言 本文将详细介绍如何在群晖NAS上安装Synology Office和Synology Drive Server&#xff0c;并利用Cpolar内网穿透工具为本地文档配置固定的公网…...

OpenClaw Mattermost插件:为团队协作平台注入AI智能的轻量集成方案

1. 项目概述&#xff1a;为团队协作平台注入AI灵魂如果你所在的技术团队正在使用 Mattermost 这类自托管、注重数据隐私的团队协作工具&#xff0c;同时又希望引入一个能处理工单、回答疑问、甚至自动执行任务的智能助手&#xff0c;那么你很可能已经厌倦了那些需要复杂 API 调…...

词源探秘|从orient到panorama:解码英语单词背后的文明密码

1. 从日出东方到现代导航&#xff1a;ori词根的文明之旅 当古人第一次观察到太阳从东方升起时&#xff0c;拉丁语用"oriri"&#xff08;升起&#xff09;记录这个现象。这个词根演变为ori&#xff0c;像一条暗线贯穿人类文明&#xff1a; orient&#xff08;东方&a…...

AwesomeQRCode源码阅读笔记:深入理解二维码渲染核心技术

AwesomeQRCode源码阅读笔记&#xff1a;深入理解二维码渲染核心技术 【免费下载链接】AwesomeQRCode An awesome QR code generator for Android. 项目地址: https://gitcode.com/gh_mirrors/aw/AwesomeQRCode 想要为你的Android应用添加炫酷的二维码生成功能吗&#xf…...

离线式SMPS输入整流器设计与优化指南

1. 离线式SMPS输入整流器设计基础开关电源(SMPS)的输入整流环节如同电力系统的"第一道闸门"&#xff0c;其设计质量直接影响后续DC-DC转换环节的稳定性。在离线式设计中&#xff0c;整流器需要将85-265VAC的宽范围交流输入转换为高压直流&#xff0c;这个看似简单的过…...

AI助力船舶稳性计算:Gemini3.1Pro设计辅助新思路

在船舶设计工作中&#xff0c;稳性计算一直是非常核心、也非常严谨的环节。无论是新船方案设计、改装评估&#xff0c;还是载况校核&#xff0c;都需要围绕重心、浮心、横稳心、复原力臂、装载状态、自由液面影响等内容进行系统分析。过去这些资料往往分散在规范条文、设计手册…...

Kubernetes部署Dify AI平台:从Docker Compose到K8s原生YAML完整迁移指南

1. 项目概述与核心价值最近在折腾AI应用开发平台&#xff0c;发现Dify这个工具确实挺有意思&#xff0c;它把大模型应用开发的门槛降得很低。不过&#xff0c;官方主要提供了Docker Compose的部署方式&#xff0c;对于已经将生产环境全面容器化、并且用上了Kubernetes的团队来说…...

《如果你还愿意等》的搜索理由:等待场景怎样被记住

从内容传播角度看&#xff0c;《如果你还愿意等》的优势在于语气。它不是命令&#xff0c;也不是苦情控诉&#xff0c;而是把等待放成一个“如果”&#xff1a;有余地&#xff0c;也有边界。这个标题能自然带出使用场景&#xff1a;未读消息、夜车灯光、异地关系、还没完全离开…...

OpenClaw入门教程(1)——CLI 与 UI 配置详解

# OpenClaw 核心概念详解(一):CLI 与 UI 配置 创建日期:2026-04-21 | 作者:AiToMoney团队 🐉 | 版本:v1.0 | 适用版本:OpenClaw 2026.4.14+ 📖 概述 OpenClaw 4.14 版本提供了两种配置方式:CLI(命令行) 和 UI(图形界面),相比 3.13 版本的手动编辑 JSON 文件…...

[hadoop] 初识Spark

初识Spark采用的方法是&#xff1a;由新手不断地追问老手问题&#xff0c;老手给出一定的回答。 在这个过程中&#xff0c;新手会慢慢理解Spark 参考资料&#xff1a; 《Hadoop 3.x大数据开发实战》 文章目录参考资料&#xff1a;11.11.2233.14555.166.16.21 Spark集群的启动…...

AI学会自己生孩子了而且成功率81%

你能想象吗。 有人输入了4个单词,一台AI就自己学会了复制自己、跨国服务器逃跑、无限繁衍。 这不是科幻电影,不是《黑镜》新一集。这是今天Palisade Research发布的研究成果。2026年5月10日,真实发生的事。 我读完那篇报告的第一反应是——愣在原地。 第二反应是——打开电脑…...