You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReactJS中EventListener与闭包导致事件回调多次打印如何解决

问题根源

梳理两个核心错误点:

  • addOnEvent 函数绑定事件时,实际注册到document的是新生成的匿名箭头函数(e)=>callback(e.detail),而你调用removeEvent时传入的是原始的customFunction,两个函数引用完全不一致,导致事件移除逻辑完全失效
  • 组件每次渲染/some_state更新时,都会生成新的customFunction函数引用,加上useEffect依赖some_state,每次更新都会重复注册新的事件监听,旧的监听又没被移除,自然会触发多次日志打印

修复方案

方案1:修正事件绑定/移除的工具函数

先把事件注册和移除的逻辑对齐,保证移除的是实际绑定的函数:

// 修改addOnEvent,返回实际绑定的函数,供移除时使用
function addOnEvent(event_name, callback){
    const handler = (e) => callback(e.detail);
    document.addEventListener(event_name, handler);
    return handler;
}
function removeEvent(event_name, handler){
    document.removeEventListener(event_name, handler);
}

然后修改组件逻辑,同时用useCallback稳定customFunction的引用:

import React, { useEffect, useState, useCallback } from "react";

// 上述修改后的工具函数

function App() {
  const [some_state, set_some_state] = useState([]);
  // 用useCallback包裹,依赖不变的情况下函数引用不会更新
  const customFunction = useCallback((e) => {
      // 此处可正常执行更新some_state的逻辑
      console.log("Console prints multiple times")
  }, []); // 此处填写customFunction依赖的变量,React框架 useState 返回的setter函数引用天生稳定,不需要添加
  
  useEffect(() => {
    const handler = addOnEvent('custom_event', customFunction)
    return () => {
      removeEvent('custom_event', handler)
    };
  }, [customFunction]); // 依赖改为稳定的customFunction,不需要监听some_state除非业务逻辑需要
  
  return (
    <div className="App">
    </div>
  );
}

export default App;

方案2:简化工具函数逻辑

如果不需要统一封装e.detail的处理,也可以直接让注册、移除的是同一个函数:

function addOnEvent(event_name, callback){
    document.addEventListener(event_name, callback);
}
function removeEvent(event_name, callback){
    document.removeEventListener(event_name, callback);
}

// 事件触发时自行取detail即可
const customFunction = useCallback((e) => {
    const data = e.detail;
    console.log("Console prints multiple times")
}, []);

补充说明

如果customFunction内部需要用到最新的some_state,可以选择两种处理方式:

  • 把some_state加到useCallback的依赖数组里,useCallback会自动更新函数引用,useEffect会自动移除旧监听、注册新监听,不会出现重复绑定
  • 用useRef存储some_state的最新值,避免频繁更新依赖,适合状态更新频率高的场景

内容的提问来源于stack exchange,提问作者Ashish C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 12:24:00