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

为何Timeout函数返回React组件的旧状态值?

React状态更新后setTimeout仍输出旧值的原因分析

你的问题核心是JavaScript闭包特性和React组件渲染机制共同作用的结果,和状态更新是否异步、等待时长无关:

  • 每次React组件状态更新后,会重新执行组件函数生成新的渲染快照,handleChange函数也会被重新创建,每个handleChange都捕获了当前渲染周期里的num值。
  • 点击按钮时,当前的handleChange里调用setNum触发状态更新,但此时这个handleChange里的num还是旧值(比如初始的1)。
  • 1秒后执行的setTimeout回调,引用的是当前handleChange闭包里的旧num,哪怕组件已经重新渲染、界面上的num显示为新值,回调里的num依然是捕获的旧值。

验证与解决方案

要获取最新状态,有两种常用方式:

方式1:用useRef保存最新状态值

useRef的current属性是可变的,不会被闭包捕获旧值,我们可以在状态更新时同步更新ref:

export default function App() {
  const [num, setNum] = React.useState(1)
  const numRef = React.useRef(num)

  // 同步ref和状态值
  React.useEffect(() => {
    numRef.current = num
  }, [num])
 
  function handleChange() {
    setNum(prev => prev + 1)
    setTimeout(() => {
      console.log(numRef.current) // 输出最新值
    }, 1000)
  }
  
  return (
    <div>
      <button onClick={handleChange}>+</button>
      <p>{num}</p>
    </div>
  );
}

方式2:用useEffect监听状态变化

如果只是想在状态更新后执行操作,更推荐用useEffect代替setTimeout,它会在状态变化后自动触发:

export default function App() {
  const [num, setNum] = React.useState(1)
 
  function handleChange() {
    setNum(prev => prev + 1)
  }

  // num更新时触发
  React.useEffect(() => {
    console.log(num) // 输出最新值
  }, [num])
  
  return (
    <div>
      <button onClick={handleChange}>+</button>
      <p>{num}</p>
    </div>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 02:32:34