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
相关产品推荐
相关产品推荐

