React useEffect Hook异常:无清理函数时定时器计数器运行到10卡顿停止
异常发生的原因
你的代码运行出现卡顿停止的核心问题是定时器泄漏+闭包陷阱,具体执行逻辑如下:
useEffect的依赖项设置为count,意味着每次count值更新时,整个useEffect回调都会重新执行一次- 你注释了定时器清理逻辑,上一次useEffect执行创建的定时器不会被销毁,会一直驻留在内存中运行
- 每个定时器都捕获了创建时对应渲染闭包内的
count固定值,比如首次渲染创建的定时器永远只会执行setCount(0 + 1),第二次渲染创建的定时器永远只会执行setCount(1 + 1),以此类推 - 随着count值上涨,后台并行运行的定时器数量会线性增长,运行几秒后就会有数十个定时器同时触发:一方面大量定时器占用JS线程资源导致页面卡顿,另一方面大量重复的setState调用触发频繁重渲染,最终会阻塞JS线程,导致计数器停止更新。
添加清理函数后恢复正常的原因
当你放开注释的清理函数逻辑后:
- 每次useEffect重新执行前,都会先触发上一次useEffect返回的清理函数,把前一个旧定时器销毁,全程只会有1个定时器在后台运行
- 每次新创建的定时器捕获的是当前最新的count值,所以会按预期每秒执行一次自增逻辑,计数器自然就正常运行了。
更优的实现方案
你可以用setState的函数式更新写法,不需要把count加入useEffect依赖,也不用频繁销毁重建定时器,性能更好:
import { useState, useEffect } from "react"; function App() { const [count, setCount] = useState(0); useEffect(() => { const interval = setInterval(() => { // 函数式更新可以直接拿到上一轮的最新state值,不需要依赖外部count变量 setCount(prevCount => prevCount + 1); }, 1000); return () => clearInterval(interval); }, []); // 空依赖,useEffect只会在组件挂载时执行一次 return ( <div className="App"> <h1>{count}</h1> </div> ); } export default App;
内容的提问来源于stack exchange,提问作者Abhinav Dhiman
相关产品推荐
相关产品推荐

