React中setInterval内结合useState使用if条件不生效如何解决
问题原因
- 你的useEffect没有传入依赖数组,每次组件状态更新触发重渲染时都会重新执行,不断创建新的定时器,导致进度增长速度远超预期。
- 定时器ID存储在普通局部变量progressTimer中,每次组件重渲染都会重置该变量,执行clearInterval时根本无法拿到之前创建的定时器ID,导致定时器无法被正常清除。
- handleTime函数通过闭包捕获的progress值是初始化时的旧值,判断逻辑无法正确匹配最新的状态,也会导致清除逻辑失效。
修复方案
修改后的完整代码如下:
import { useState, useEffect, useRef } from "react"; import "./styles.css"; export default function App() { const [progress, setProgress] = useState(0); // 使用useRef存储定时器ID,跨渲染周期保持引用不变 const progressTimerRef = useRef(null); function handleTime() { setProgress((prevState) => { if (prevState < 100) { return prevState + 10; } else { // 进度达到阈值后清除定时器 clearInterval(progressTimerRef.current); return prevState; } }); } function handlePlay() { progressTimerRef.current = setInterval(handleTime, 1000); } useEffect(() => { handlePlay(); // 组件卸载时清除定时器,避免内存泄漏 return () => clearInterval(progressTimerRef.current); }, []); // 空依赖数组,仅在组件挂载时执行一次,避免重复创建定时器 return ( <div className="App"> <h1>Hello CodeSandbox</h1> {progress} <h2>Start editing to see some magic happen!</h2> </div> ); }
核心修改点
- 给useEffect添加空依赖数组,仅在组件首次挂载时启动一次定时器,避免重复创建
- 用useRef存储定时器ID,保证所有渲染周期都可以访问到同一个定时器实例,清除操作可以正常生效
- 把进度阈值判断放到setProgress的回调函数中,直接获取最新的状态值,规避闭包捕获旧状态的问题
- 新增useEffect的清理回调,组件卸载时自动清除定时器,避免内存泄漏
内容的提问来源于stack exchange,提问作者Jon
相关产品推荐
相关产品推荐

