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

500字理透react的hook闭包问题

在react中hook的闭包问题很容易在不经意间犯错,项目写大了之后更是难以找到到底是哪里出了问题。

为什么会出现闭包问题

出现闭包问题的原因就是函数中操作的变量不是最新的变量,什么意思呢,我们知道函数组件每次刷新都是重新运行一次函数,这就会导致,每次刷新都会产生新的变量,但是如果用useEffect把依赖性置为空数组的话,那么useEffect中的回调就不会再次执行,导致回调中保存的仍是刷新前的变量。

代码
import { useEffect } from "react";
import { useState } from "react";

function App() {

  const [count, setCount] = useState(0);


  useEffect(() => {
    const interval = setInterval(() => {
      setCount(count + 1);
    }, 500);
    return () => {
      clearInterval(interval)
    };
  }, []);


  return (
    <div>
      {count}  
    </div>
  );
}

export default App;

运行效果如下

请添加图片描述

我们可以看到代码并没有我们预期的结果,加到1就停止增加了,为什么呢?
我们分析一下APP函数的运行次数。
第一次运行count = 0过一秒钟后因为会setCount导致count = 1然后刷新页面,重新运行APP函数,在内存中生成新的count变量,useEffect因为依赖项为[]所以不在再次执行,setInterval中的函数保存的还是第一次函数执行的count变量,setInterval后续的每次执行操作的都是第一次的变量导致一直setCount(0 + 1),App函数并不会再次刷新了。
看图

在这里插入图片描述

现在知道了闭包的产生原因,就是因为函数中操作的变量不是最新的,那解决办法就很明显了。

  • 函数前后刷新都会产生新的变量,那我们让他不产生新的不就可以了,这就可以使用useRef这个钩子了。
import { useEffect, useRef } from "react";
import { useState } from "react";

function App() {

  const countRef = useRef(0);
  const [_, forceUpdate] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      console.log('count', countRef.current)
      countRef.current += 1;
      forceUpdate(Math.random())
    }, 500);
    return () => {
      clearInterval(interval)
    };
  }, []);


  return (
    <div>
      {countRef.current}  
    </div>
  );
}

export default App;

在这里插入图片描述
操作方式

在这里插入图片描述

  • 每次组件刷新的时候都让函数重新执行,让函数去操作最新变量就可以了
import { useEffect } from "react";
import { useState } from "react";

function App() {

  const [count, setCount] = useState(0);


  useEffect(() => {
    const interval = setInterval(() => {
      setCount(count + 1);
    }, 500);
    return () => {
      clearInterval(interval)
    };
  }, [count]);


  return (
    <div>
      {count}  
    </div>
  );
}

export default App;

操作方式

  • 闭包导致了这个问题,那我们就不让他产生闭包,这就用到了setCount的另一个重载的形式。
import { useEffect } from "react";
import { useState } from "react";

function App() {

  const [count, setCount] = useState(0);


  useEffect(() => {
    const interval = setInterval(() => {
      // 使用箭头函数,可以获取到最新的count值
      setCount(count => count + 1);
    }, 500);
    return () => {
      clearInterval(interval)
    };
  }, []);


  return (
    <div>
      {count}  
    </div>
  );
}

export default App;

我们把函数传入setCount中,在setCount执行的时候会自动把最新的count值传入,就不会出现闭包导致每次操作的count都是0的情况了。

创造不易,喜欢留下个👍 吧

相关文章:

  • RPC 框架项目剖析
  • 网络和操作系统基础篇
  • Python pip 缓存清理:全面方法与操作指南
  • 【算法通关村 Day9】二分查找与二叉树的中序遍历
  • 人工智能_大模型092_超简单_win10中安装deepseek_效果非常好_亲测_带RGA功能_桌面版---人工智能工作笔记0237
  • 【2025全网首发B站教程】YOLOv12训练数据集构建:标签格式转换-划分-YAML 配置 避坑指南 | 小白也能轻松玩转目标检测!
  • [oAuth2授权]Web前端+NodeCoze API Web后端程序+Coze授权服务器工作流程架构流程图详解
  • 在Ubuntu下通过Docker部署Nginx服务器
  • 6. Go接口
  • C++双指针:算法优化的“左右互搏术”与高效问题破解全指南
  • 蓝桥杯备赛-基础训练(三)哈希表 day16
  • 力扣-回溯-332 重新安排行程
  • 基于Flask的短视频流量数据可视化系统的设计与实现
  • 高速PCB电源层
  • Linux 使用nload 监控网络流量
  • Git入门:数据模型 to 底层原理
  • MQTT实现智能家居------2、写MQTT程序的思路
  • 电子技能大赛选题
  • 腿足机器人之十二-manipulation
  • 超过7万个AOI(地理围栏),北京市2025年2月15日更新的全类别AOI,本地矢量数据(全国22个超大特大城市AOI更新系列)
  • 五一去哪玩?“时代交响”音乐会解锁艺术假期
  • 光明日报社论:用你我的匠心,托举起繁盛的中国
  • 美乌矿产协议签署被曝“临门一脚”时生变,美方提附加条件
  • 浪尖计划再出发:万亿之城2030课题组赴九城调研万亿产业
  • 魔都眼|静安光影派对五一启幕:苏河湾看徐悲鸿艺术画作
  • 国铁集团郑州局预计“五一”发送642.5万人