React中setInterval与clearInterval引发状态重复问题求助
React基础倒计时器问题解决
问题描述
你需要实现一个初始30秒的React倒计时器,点击按钮可重置并重新开始倒计时。最初未更新状态时控制台输出正常,但启用setSeconds更新页面渲染后,出现console.log重复、渲染加倍、双重倒计时同时运行的异常。
原始代码
const [seconds, setSeconds] = useState(30) let interval = null function startTimer() { stopTimer() let start = 30 interval = setInterval(() => { // setSeconds(start) console.log('start: ', start) start-- }, 1000) } function stopTimer() { clearInterval(interval) } return ( <p>{seconds}s</p> <button onClick={startTimer}>Start</button> )
问题根源
- 组件内部声明的
interval变量会随每次渲染重新初始化,无法有效追踪定时器实例 - React开发环境的StrictMode会触发两次渲染,导致多个定时器实例同时运行,进而引发重复日志和状态异常更新
解决方案
使用useRef保存定时器引用(其值在组件生命周期内保持稳定),结合函数式状态更新确保状态同步:
import { useState, useRef, useEffect } from 'react'; function CountdownTimer() { const [seconds, setSeconds] = useState(30); const intervalRef = useRef(null); function startTimer() { // 清除已有定时器 if (intervalRef.current) { clearInterval(intervalRef.current); } // 重置秒数 setSeconds(30); // 启动新定时器 intervalRef.current = setInterval(() => { setSeconds(prevSeconds => { if (prevSeconds <= 1) { clearInterval(intervalRef.current); return 0; } return prevSeconds - 1; }); }, 1000); } // 组件卸载时清理定时器,避免内存泄漏 useEffect(() => { return () => { intervalRef.current && clearInterval(intervalRef.current); }; }, []); return ( <div> <p>{seconds}s</p> <button onClick={startTimer}>Start/Reset</button> </div> ); } export default CountdownTimer;
关键改动说明
useRef存储定时器引用:确保跨渲染周期保持同一引用,避免丢失对定时器的追踪- 函数式状态更新:
setSeconds(prevSeconds => ...)保证每次获取最新的状态值,避免闭包导致的状态滞后 - 卸载清理:通过
useEffect的清理函数在组件卸载时清除定时器,防止内存泄漏 - 自动终止逻辑:倒计时至0时主动清除定时器,避免无效的定时器运行
内容的提问来源于stack exchange,提问作者Eric Winkelspecht
相关产品推荐
相关产品推荐

