React中使用useState管理复杂对象状态未按预期生效
你设置order状态的写法是正确的,问题出在定时器的使用逻辑存在闭包陷阱,具体原因和修复方案如下:
问题原因
setInterval直接写在组件函数顶层,组件每重渲染一次就会创建一个新的定时器实例,本身就会导致逻辑混乱和内存泄漏。- 首次渲染创建的定时器回调捕获了当时的闭包变量,其中
order是初始值(IsRetrieving为true),后续状态更新后,旧定时器回调的闭包变量不会同步更新,所以永远读不到最新的order.IsRetrieving值,也就无法触发清除逻辑。 - 同理回调中的
fetchCheckerCounter也永远是初始值0,你原本设计的文案切换逻辑也无法正常执行。
修复方案
将定时器逻辑放到useEffect中管理,将依赖的状态加入依赖数组,每次依赖变化时自动清理旧定时器、创建新的定时器,即可拿到最新的状态值:
const [fetchCheckerCounter, setFetchCheckerCount] = useState<number>(0); useEffect(() => { // 已经请求完成则不创建定时器 if (!order.IsRetrieving) return; const statusFetcherWatcher = setInterval(() => { if (fetchCheckerCounter === 1) { setOrder(salesOrder => ({...salesOrder, RetrievingMsg: "This can take a few seconds..."})); } else if (fetchCheckerCounter === 2) { setOrder(salesOrder => ({...salesOrder, RetrievingMsg: "Almost there!.."})); } setFetchCheckerCount(prev => prev + 1); }, 7000); // 依赖变化或组件卸载时自动清理定时器 return () => clearInterval(statusFetcherWatcher); }, [order.IsRetrieving, fetchCheckerCounter]);
可选优化
你也可以通过useRef存储最新的order和fetchCheckerCounter状态,避免每次状态变化都重建定时器,进一步优化性能。
内容的提问来源于stack exchange,提问作者abc
相关产品推荐
相关产品推荐

