React进度条中useEffect内定时器无法获取最新状态问题
React进度条定时器无法获取最新状态的解决方案
你遇到的是React中常见的闭包陷阱问题:useEffect创建的定时器回调会捕获初始渲染时的state快照,即便后续state更新,定时器里拿到的还是旧值,频繁点击重置后,新旧定时器的状态冲突就会暴露这个问题。
下面是两种可靠的解决方式:
方案一:使用函数式更新修改状态
React的setState支持传入函数,函数参数会自动获取最新的state值,完全避开闭包带来的旧值引用问题:
import { useState, useEffect, useRef } from 'react'; function ProgressBar() { const [progress, setProgress] = useState(0); const timerRef = useRef(null); // 启动定时器逻辑 const startTimer = () => { timerRef.current = setInterval(() => { setProgress(prevProgress => { if (prevProgress >= 100) { clearInterval(timerRef.current); return 100; } return prevProgress + 10; }); }, 1000); }; // 初始启动定时器 useEffect(() => { startTimer(); return () => clearInterval(timerRef.current); }, []); // 重置按钮逻辑 const handleReset = () => { clearInterval(timerRef.current); setProgress(0); startTimer(); }; return ( <div> <div style={{ width: `${progress}%`, height: '20px', backgroundColor: 'blue' }}></div> <button onClick={handleReset}>重置</button> </div> ); }
方案二:用useRef保存最新状态
把进度值同步到useRef中,定时器直接访问ref.current获取最新状态,不受闭包影响:
import { useState, useEffect, useRef } from 'react'; function ProgressBar() { const [progress, setProgress] = useState(0); const progressRef = useRef(0); const timerRef = useRef(null); // 同步state到ref,确保ref始终持有最新进度值 useEffect(() => { progressRef.current = progress; }, [progress]); const startTimer = () => { timerRef.current = setInterval(() => { if (progressRef.current >= 100) { clearInterval(timerRef.current); return; } const newProgress = progressRef.current + 10; progressRef.current = newProgress; setProgress(newProgress); }, 1000); }; useEffect(() => { startTimer(); return () => clearInterval(timerRef.current); }, []); const handleReset = () => { clearInterval(timerRef.current); progressRef.current = 0; setProgress(0); startTimer(); }; return ( <div> <div style={{ width: `${progress}%`, height: '20px', backgroundColor: 'blue' }}></div> <button onClick={handleReset}>重置</button> </div> ); }
这两种方案都能解决定时器获取旧状态的问题,其中方案一更简洁,推荐优先使用函数式更新的方式。
内容的提问来源于stack exchange,提问作者Laxmi Prasanna Rokkam
相关产品推荐
相关产品推荐

