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

React视图已更新但state变量未同步更新的原因解析

React State闭包陷阱:为什么第二个setTimeout里的state还是初始值?

问题代码

import { useEffect, useState } from "react";

export default function App() {
  const [a, setA] = useState(["initial"]);

  useEffect(() => {
    setTimeout(() => {
      setA(["hello"]);
    }, 1000);
  
    setTimeout(() => {
      setA([...a, " world"]);
    }, 2000);
  }, []);

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

实际表现

0 sec: initial
1 sec: hello
2 sec: initial world

预期结果

0 sec: initial
1 sec: hello
2 sec: hello world


原因分析

这是React闭包陷阱导致的:

  • useEffect的依赖数组为空,意味着它只在组件首次挂载时执行一次。
  • 执行useEffect时,两个setTimeout的代码会捕获当前作用域下的a值——也就是组件挂载时的初始值["initial"]。
  • 即使第一个setTimeout在1秒后修改了state、触发组件重新渲染,但第二个setTimeout里的a还是挂载时捕获的旧值,不会跟着更新。

解决方案

使用函数式更新获取最新state值,setState支持传入一个函数,函数的参数就是当前最新的state:

import { useEffect, useState } from "react";

export default function App() {
  const [a, setA] = useState(["initial"]);

  useEffect(() => {
    setTimeout(() => {
      setA(["hello"]);
    }, 1000);
  
    setTimeout(() => {
      // 用函数式更新,prev为当前最新的state
      setA(prev => [...prev, " world"]);
    }, 2000);
  }, []);

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

这样第二个setTimeout执行时,会拿到第一个setA更新后的最新state,最终就能得到hello world的预期结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 10:33:19