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

