You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中状态更新快于异步alert显示取旧值的问题该如何解决?

问题原因

这是React函数式组件典型的闭包陷阱问题:函数式组件每次渲染都会生成全新的函数实例,你点击check count触发checkCurrentCount时,该函数已经捕获了当前渲染周期下的count常量值,后续你点击+更新状态触发组件重渲染,生成的新count变量和已经在等待执行的setTimeout回调里引用的count属于不同渲染周期的独立变量,因此回调执行时只能拿到触发时的旧值。

解决方案

使用useRef存储状态的最新引用是兼容性最好的通用方案,ref的current属性为可变值,所有渲染周期共享同一个引用,读取时永远可以拿到最新的状态值。
修改后的代码如下:

import React, { useEffect, useRef } from 'react';

const Comp2 = () => {
  const [count, setCount] = React.useState(0);
  // 定义存储count最新值的ref
  const countRef = useRef(count);

  // 每次count更新时同步更新ref的current值
  useEffect(() => {
    countRef.current = count;
  }, [count]);

  const handleIncrease = () => {
    setCount((x) => x + 1);
  };

  const checkCurrentCount = () => {
    console.log('checking...');
    setTimeout(() => {
      // 读取ref里的最新值
      alert(`Ok the current count is: ${countRef.current}`);
    }, 2000);
  };

  return (
    <div>
      <p>{count}</p>
      <button onClick={handleIncrease}>+</button>
      <button onClick={checkCurrentCount}>check count</button>
    </div>
  );
};
其他可选方案

如果你使用的是React 18及以上版本,也可以使用实验性APIuseEvent来封装回调,无需手动维护ref,useEvent包裹的函数永远可以拿到最新的props和state:

import React, { unstable_useEvent as useEvent } from 'react';

const Comp2 = () => {
  const [count, setCount] = React.useState(0);

  const handleIncrease = () => {
    setCount((x) => x + 1);
  };

  // 用useEvent包裹回调
  const showCount = useEvent(() => {
    alert(`Ok the current count is: ${count}`);
  });

  const checkCurrentCount = () => {
    console.log('checking...');
    setTimeout(showCount, 2000);
  };

  return (
    <div>
      <p>{count}</p>
      <button onClick={handleIncrease}>+</button>
      <button onClick={checkCurrentCount}>check count</button>
    </div>
  );
};

内容的提问来源于stack exchange,提问作者metalheadcoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 05:24:06