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

