为什么useEffect Hook中addEventListener会出现事件累加现象?
问题解答
1. Hook外定义的EventListener运行逻辑
所有写在组件函数、Hook之外的顶层代码,都会在当前模块第一次被导入时仅执行一次,和组件的渲染、卸载生命周期完全无关。
也就是说这个监听会在你的组件文件被加载时就绑定到对应目标上,绑定的回调是初始定义的版本,闭包永远引用初始状态的变量,后续组件无论重渲染多少次,顶层代码都不会重复执行,所以这个监听不会重复绑定,回调逻辑也不会跟着组件状态更新。
2. 点击列表项触发次数翻倍的原因
你在useEffect里绑定的EventListener没有配置清理逻辑,每次组件重渲染时:
- 如果你的useEffect没有传依赖数组,每次组件重渲染都会重新执行一遍useEffect的回调
- 每次执行回调就会调用一次addEventListener,给同一个DOM的点击事件队列新增一个回调函数
浏览器触发点击事件时,会按绑定顺序依次执行所有队列里的回调,你看到翻倍就是组件已经重渲染过一次,先后绑定了两个相同的点击回调,点一次就会触发两次。
3. addEventListener需要清理、console.log不会累加的原因
addEventListener是浏览器提供的DOM API,它的核心特性是主动绑定、持久存储:你每次调用它,都会给对应DOM节点的对应事件注册一个永久生效的回调,直到你主动调用removeEventListener移除,或者DOM节点被销毁,浏览器不会自动清理你注册的回调,哪怕触发注册逻辑的组件已经重渲染/卸载了。
而console.log只是普通的同步执行函数,每次调用只会当场执行一次输出逻辑,执行完成后就直接结束,不会在内存中留存任何待触发的回调函数,自然不存在累加的问题。
内容的提问来源于stack exchange,提问作者Anthony
相关产品推荐
相关产品推荐

