如何停止定义在useEffect外部的setInterval 解决React进度条更新异常问题
问题根因
- 定时器创建位置错误:
setInterval直接写在组件顶层,每次状态更新触发组件重渲染时都会生成新的定时器,多个定时器并行运行导致状态更新异常 - 闭包陷阱:定时器回调中读取的
percentage是初始化时的静态值,不会跟随状态更新变化,数值累加逻辑不符合预期 - 定时器ID无法共享:每次重渲染都会重新声明
progressInterval变量,判断条件中拿到的不是当前运行的定时器ID,导致clearInterval无法生效 - 时间配置不符需求:原代码定时器间隔写为
10000(10秒),和要求的5秒递增不符
修复后完整代码
import {useState, useEffect, useRef} from 'react'; function App() { const [percentage,setPercentage] = useState(99) // 用ref存储定时器ID,全渲染周期共享 const progressIntervalRef = useRef(null) // 仅组件首次挂载时创建一次定时器 useEffect(() => { progressIntervalRef.current = setInterval(()=>{ // 函数式更新状态,避开闭包陷阱 setPercentage(prev => prev + 1); },5000); // 组件卸载时自动清理定时器,避免内存泄漏 return () => clearInterval(progressIntervalRef.current) }, []) useEffect(() => { if(percentage === 100) { console.log("completed"); clearInterval(progressIntervalRef.current); } }, [percentage]) const progress = { backgroundColor: 'yellow', width: `${percentage}%`, textAlign: 'right', } const fullWidth = { border: '1px solid black', backgroundColor: '#eff', margin: '10px' } return ( <> <div style={fullWidth}> <div style={progress}>{percentage}%</div> </div> </> ); } export default App;
核心修改说明
- 新增
useRef存储定时器ID,保证所有渲染过程中读取的是同一个定时器实例,可正常清除 - 将定时器创建逻辑移入仅执行一次的
useEffect中,避免重复生成多个定时器 - 状态更新改用函数式写法,直接读取上一次的最新状态,避开闭包导致的旧值问题
- 增加组件卸载时的定时器清理逻辑,避免内存泄漏
- 将定时器间隔调整为
5000,匹配5秒递增的需求
内容的提问来源于stack exchange,提问作者vivek modi
相关产品推荐
相关产品推荐

