React使用setInterval实现倒计时出现最大更新深度超限报错问题
问题根因
- CountDownTimer组件的
useEffect未指定依赖数组,会在每一次组件重渲染时都执行回调:- 倒计时运行时,每秒
setTime更新时间触发重渲染,都会创建新的setInterval实例,最终同时存在大量倒计时定时器 - 点击停止按钮时
ticking变为false,useEffect会执行reset函数调用setTime重置时间,再次触发组件重渲染,重渲染又会执行useEffect调用reset,形成无限更新循环,触发最大更新深度超限警告
- 倒计时运行时,每秒
修复方案
步骤1:给useEffect添加依赖数组
仅当ticking、defaultMinutes、defaultSeconds变化时才执行回调,避免无意义的重复执行
步骤2:修改tick为函数式更新状态
避免闭包捕获旧的mins、secs值导致倒计时异常
修复后完整CountDownTimer代码:
import { FC, useState, useEffect, useRef } from "react"; interface CountDownTimerProps { defaultMinutes: number; defaultSeconds: number; ticking: boolean; } const CountDownTimer: FC<CountDownTimerProps> = (props) => { const { defaultMinutes, defaultSeconds, ticking } = props; const [[mins, secs], setTime] = useState([defaultMinutes, defaultSeconds]); const timerId = useRef<NodeJS.Timeout | null>(null); const stopTimerInterval = () => timerId.current !== null && clearInterval(timerId.current); const tick = () => { setTime(prev => { const [prevMins, prevSecs] = prev if (prevMins === 0 && prevSecs === 0) { return prev; } else if (prevSecs === 0) { return [prevMins - 1, 59]; } else { return [prevMins, prevSecs - 1]; } }) }; const reset = () => { stopTimerInterval(); setTime([defaultMinutes, defaultSeconds]); }; // 添加依赖数组 useEffect(() => { if (!ticking) { reset(); return; } else { timerId.current = setInterval(() => tick(), 1000); console.log("creating interval"); } return () => { stopTimerInterval(); }; }, [ticking, defaultMinutes, defaultSeconds]); // 依赖列表 return ( <p className="text-white text-5xl">{`${mins.toString().padStart(2, "0")}:${secs .toString() .padStart(2, "0")}`}</p> ); }; export default CountDownTimer;
内容的提问来源于stack exchange,提问作者Skyler Brandt
相关产品推荐
相关产品推荐

