react 定时器内闭包的存在导致 数据无法及时更新

需求:React Hooks useEffect使用定时器,每3秒更新一次值

代码如下:

javascript 复制代码
 const [MyV, setMyV] = useState(0);

  useEffect(() => {
    // 每隔3s,增加1
    const interval = setInterval(() => {
      setMyV(MyV+1);
    }, 3 * 1000);
    return () => {
      clearInterval(interval);
    };
  }, []);

实际,页面展示MyV 一直是 1。 因为setInterval会行程一个闭包。此闭包内用到的的上下文的state都是创建时的初始值。因此 setMyV(MyV+1); 时,MyV一直都是 0

优化方法1 :setMyV的函数形式

适用于此案例,只涉及一个state的变更

原理分析: setMyV((v) => v + 1); 里的v不属于闭包内部的变量,而是一个形参,因此不会一直使用0+1,而是最新的数据+1

javascript 复制代码
  const interval = setInterval(() => {
      setMyV((v) => v + 1);
    }, 3 * 1000);
优化方法2 :使用ref

适用于复杂案例,或许会涉及多个state的变更、甚至更多代码、方法、state的关联调用

原理分析:useRef 返回一个具有单个 current 属性 的 ref 对象,并初始化为你提供的 初始值。

且 在后续useRef 将返回相同的对象

因此,在此setInterval的闭包里,它只会关注myRef这个ref对象指向的地址 ,不再变化即可。myRef内部的current属性千变万化,以及myRef.current内部的其他属性用到的其它state (此处指MyV)也都是最新的。

javascript 复制代码
  const [MyV, setMyV] = useState(0);
  const myRef: any = useRef();
  myRef.current = () => {
    setMyV(MyV + 1);
    //只要是在这里访问、处理的,永远是最新的数据
    //...
  };
  useEffect(() => {
    // 每隔3s,增加1
    const interval = setInterval(() => {
      myRef.current();
    }, 3 * 1000);
    return () => {
      clearInterval(interval);
    };
  }, []);

参考:react官网对useRef的描述

相关推荐
架构师汤师爷2 分钟前
一文彻底搞懂 OpenClaw 的架构设计与运行原理(万字图文)
前端·agent
苑若轻航3 分钟前
防抖和节流:解决高频事件性能
前端
小黑的铁粉6 分钟前
什么是事件循环?调用堆栈和任务队列之间有什么区别?
前端·javascript
小黑的铁粉6 分钟前
常见的内存泄漏有哪些?
前端·javascript
喝水的长颈鹿7 分钟前
JavaScript 基础入门
前端
喝咖啡的女孩8 分钟前
call、apply、bind 原理与实现
前端
雨落Re8 分钟前
从设计到开发,过年我用十天使用AI搭建了一个完整的博客系统
前端·后端
冴羽18 分钟前
100s 带你了解 Bun 为什么这么火
前端·node.js·bun
Sylvia33.21 分钟前
火星数据:解构斯诺克每一杆进攻背后的数字语言
java·前端·python·数据挖掘·数据分析
pe7er35 分钟前
React 状态管理:Easy-Peasy 入门指南
react.js