useEffect未配置清理函数导致点击计数非预期递增的原因是什么?
问题原因分析
大量事件监听器的挂载逻辑
你写的useEffect没有传入第二个依赖数组参数,按照React的规则,这种写法下每次组件渲染完成后都会执行一次useEffect的回调函数:
- 组件初次加载会触发第一次渲染,useEffect执行,新增第一个mousedown监听
- 后续每次调用
setClickCount更新状态都会触发组件重渲染,每重渲染一次,useEffect就会再执行一次,新增一个新的mousedown监听 - 旧的监听没有做清理,会一直挂载在document对象上,监听器的数量会随着渲染次数线性增长。
对计数结果的影响逻辑
你用的是函数式更新写法setClickCount(prev => prev + 1),这种写法每次都会拿到当前最新的count值做更新,所以所有挂载的监听器触发的更新都会生效:
- 初次渲染完成后,仅存在1个监听器,点击一次触发1次更新,count从0变成1,触发重渲染
- 重渲染后新增1个监听器,此时总共2个监听器,点击一次触发2次更新,count从1变成1+2=3,再次触发重渲染
- 若这次重渲染过程中因为其他逻辑多触发了一次渲染,就会累计到4个监听器,点击一次触发4次更新,count从3变成3+4=7,和你观察到的现象一致。
本质上每次点击的增量等于当前已挂载的监听器总数量,所以count不会按预期每次加1,而是会越来越快地增长。
修复方案
只要给useEffect补充清理逻辑,同时指定空依赖数组,让监听只挂载一次即可:
useEffect(() => { document.addEventListener('mousedown', increment); // 清理函数,组件卸载时自动移除监听 return () => document.removeEventListener('mousedown', increment); }, []);
内容的提问来源于stack exchange,提问作者Hussam
相关产品推荐
相关产品推荐

