
本文详解如何在 react 函数组件中借助 useeffect 和 settimeout 实现三个 div 的循环背景色切换,避免因重复渲染导致的定时器混乱与内存泄漏问题。
本文详解如何在 react 函数组件中借助 useeffect 和 settimeout 实现三个 div 的循环背景色切换,避免因重复渲染导致的定时器混乱与内存泄漏问题。
在 React 中直接于组件顶层调用 setTimeout 是常见误区:每当状态更新触发重渲染时,组件函数会重新执行,导致 setTimeout 被反复注册,多个定时器并发运行,最终造成状态冲突、闪烁异常甚至内存泄漏。
正确做法是将定时逻辑封装在 useEffect 钩子中,并利用其仅在组件挂载时执行一次的特性(通过传入空依赖数组 []),同时务必在清理函数中调用 clearTimeout,防止组件卸载后仍尝试更新已销毁的状态。
以下是优化后的完整实现:
import { useState, useEffect } from 'react';
function App() {
const [redBgColor, setRedBgColor] = useState('');
const [yellowBgColor, setYellowBgColor] = useState('');
const [greenBgColor, setGreenBgColor] = useState('');
useEffect(() => {
let timerId;
// 启动初始状态(红灯)
const start = () => {
setRedBgColor('#FF0000');
setYellowBgColor('');
setGreenBgColor('');
timerId = setTimeout(wait, 4000);
};
const wait = () => {
setRedBgColor('');
setYellowBgColor('#FBFF00');
setGreenBgColor('');
timerId = setTimeout(go, 2000);
};
const go = () => {
setRedBgColor('');
setYellowBgColor('');
setGreenBgColor('#00FF00');
timerId = setTimeout(start, 5000);
};
// 延迟 100ms 后启动流程(模拟初始化延迟)
timerId = setTimeout(start, 100);
// 清理函数:组件卸载时清除定时器
return () => {
if (timerId) clearTimeout(timerId);
};
}, []); // 仅在挂载时执行
return (
<div classname="container">
<div classname="flexbox-container">
<div classname="flexbox-item flexbox-item-1" style="{{" backgroundcolor: redbgcolor></div>
<div classname="flexbox-item flexbox-item-2" style="{{" backgroundcolor: yellowbgcolor></div>
<div classname="flexbox-item flexbox-item-3" style="{{" backgroundcolor: greenbgcolor></div>
</div>
</div>
);
}
export default App;
关键要点总结:
✅ 使用 useEffect(..., []) 确保定时器逻辑只初始化一次;
✅ 将所有 setTimeout 赋值给同一变量 timerId 并持续覆盖,便于统一清理;
✅ 清理函数中必须调用 clearTimeout(timerId),避免“setState on unmounted component”警告;
✅ 初始状态建议设为 ''(空字符串)而非 null,避免 backgroundColor: 'null' 的 CSS 错误;
✅ 可进一步抽象为自定义 Hook(如 useTrafficLight)提升复用性。
该方案稳定、可维护,符合 React 官方推荐的副作用管理规范,适用于任何基于时间序列的状态轮播场景。











