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

如何在React onClick中增删同一事件监听器避免无限堆叠

解决方案

核心逻辑是通过持久化存储每个目标SVG元素对应的回调函数引用,保证addEventListener和removeEventListener操作的是同一个函数,解决监听堆叠问题。这里选用WeakMap做存储载体,以DOM元素为键,不会阻止DOM元素的垃圾回收,避免内存泄漏。

修改后完整代码:

// 定义在组件顶层作用域,不要放在barClick函数内部
const callbackMap = new WeakMap<SVGRectElement, () => void>();

const barClick = (event) => {
  const target = event.target as SVGRectElement;
  const parent = target.parentElement;
  if (!parent) return;

  // 先移除当前元素之前绑定的旧监听,避免堆叠
  const oldChangeBack = callbackMap.get(target);
  if (oldChangeBack) {
    parent.removeEventListener('click', oldChangeBack);
    callbackMap.delete(target);
  }

  // 修改当前选中柱形的颜色
  target.style.fill = cvar('colorSecondary');

  // 定义新的回调并存入WeakMap,保证后续可以拿到相同引用移除
  const changeBack = () => {
    target.style.fill = cvar('colorPrimary');
    // 回调执行后自动清理监听和存储记录
    parent.removeEventListener('click', changeBack);
    callbackMap.delete(target);
    console.log('changed');
  };
  callbackMap.set(target, changeBack);

  // 绑定新的父级点击监听
  parent.addEventListener('click', changeBack);
};

核心要点

  • 所有回调统一存在组件全局的callbackMap中,同一个元素的回调可以被精准找到并移除
  • 每次触发barClick时先清理当前元素之前绑定的旧回调,避免多次点击生成多个监听
  • changeBack执行时会自动清理自身的监听和存储记录,避免无效数据残留
  • 若组件存在卸载场景,可在useEffect的清理函数中遍历已绑定的回调做移除操作,进一步规避内存泄漏风险

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 02:06:04