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

ReactJS中如何移除已添加的事件监听器?附相关代码

如何移除React中添加的事件监听器

嘿,我懂你的困扰——你现在用匿名函数添加了mousedown、mousemove和mouseup这些事件监听器,但匿名函数的问题在于,你没法在后续用removeEventListener找到它(因为每次创建的都是新的函数实例)。下面给你几个实用的解决方案:

方案1:将事件处理函数抽为类成员方法

这是最推荐的方式,既清晰又符合React的最佳实践。你可以把每个事件的逻辑抽成类的箭头函数成员(这样不用手动绑定this),然后在添加/移除监听器时引用同一个函数实例:

首先,在组件类中定义这些处理方法:

// 定义mousedown处理函数
private handleMouseDown = (event: any) => {
  // 这里写你原来mousedown回调里的逻辑
  const parent = ReactDOM.findDOMNode(this).parentNode;
  if (parent) {
    parent.addEventListener("mousemove", this.handleMouseMove);
  }
  
  const eDrag = parent?.getElementsByClassName("draggable")[0];
  if (eDrag) {
    eDrag.addEventListener("mouseup", this.handleMouseUp);
  }
}

// 定义mousemove处理函数
private handleMouseMove = (event1: any) => {
  // 这里写你原来mousemove回调里的逻辑
}

// 定义mouseup处理函数
private handleMouseUp = (event3: any) => {
  // 这里写你原来mouseup回调里的逻辑
  
  // 记得在mouseup时移除mousemove监听
  const parent = ReactDOM.findDOMNode(this).parentNode;
  if (parent) {
    parent.removeEventListener("mousemove", this.handleMouseMove);
  }
  
  // 移除自身的mouseup监听
  const eDrag = parent?.getElementsByClassName("draggable")[0];
  if (eDrag) {
    eDrag.removeEventListener("mouseup", this.handleMouseUp);
  }
}

然后修改你的drags方法,用这些成员方法替代匿名函数:

private drags() {
  const e = ReactDOM.findDOMNode(this.container);
  if (e) {
    e.addEventListener("mousedown", this.handleMouseDown);
  }
}

最后,在组件卸载时清理所有可能残留的监听器,避免内存泄漏:

public componentWillUnmount() {
  // 移除container上的mousedown监听
  const e = ReactDOM.findDOMNode(this.container);
  if (e) {
    e.removeEventListener("mousedown", this.handleMouseDown);
  }
  
  // 清理可能存在的mousemove监听
  const parent = ReactDOM.findDOMNode(this).parentNode;
  if (parent) {
    parent.removeEventListener("mousemove", this.handleMouseMove);
  }
  
  // 清理可能存在的mouseup监听
  const eDrag = parent?.getElementsByClassName("draggable")[0];
  if (eDrag) {
    eDrag.removeEventListener("mouseup", this.handleMouseUp);
  }
}

方案2:将匿名函数存储为实例属性

如果你不想抽成单独的成员方法,也可以把每个匿名函数存到组件实例的属性上,这样后续移除时能拿到同一个引用:

修改drags方法:

private drags() {
  const e = ReactDOM.findDOMNode(this.container);
  if (e) {
    // 把mousedown函数存到实例上
    this.mouseDownHandler = (event: any) => {
      // 原来的mousedown逻辑
      const parent = ReactDOM.findDOMNode(this).parentNode;
      if (parent) {
        // 把mousemove函数存到实例上
        this.mouseMoveHandler = (event1: any) => {
          // 原来的mousemove逻辑
        }
        parent.addEventListener("mousemove", this.mouseMoveHandler);
      }
      
      const eDrag = parent?.getElementsByClassName("draggable")[0];
      if (eDrag) {
        // 把mouseup函数存到实例上
        this.mouseUpHandler = (event3: any) => {
          // 原来的mouseup逻辑
          
          // 移除监听器
          parent?.removeEventListener("mousemove", this.mouseMoveHandler);
          eDrag.removeEventListener("mouseup", this.mouseUpHandler);
          
          // 清理实例上的引用,防止内存泄漏
          delete this.mouseMoveHandler;
          delete this.mouseUpHandler;
        }
        eDrag.addEventListener("mouseup", this.mouseUpHandler);
      }
    }
    e.addEventListener("mousedown", this.mouseDownHandler);
  }
}

然后在componentWillUnmount中清理:

public componentWillUnmount() {
  const e = ReactDOM.findDOMNode(this.container);
  if (e && this.mouseDownHandler) {
    e.removeEventListener("mousedown", this.mouseDownHandler);
    delete this.mouseDownHandler;
  }
  
  const parent = ReactDOM.findDOMNode(this).parentNode;
  if (parent && this.mouseMoveHandler) {
    parent.removeEventListener("mousemove", this.mouseMoveHandler);
    delete this.mouseMoveHandler;
  }
  
  const eDrag = parent?.getElementsByClassName("draggable")[0];
  if (eDrag && this.mouseUpHandler) {
    eDrag.removeEventListener("mouseup", this.mouseUpHandler);
    delete this.mouseUpHandler;
  }
}

额外建议:用Ref替代ReactDOM.findDOMNode

ReactDOM.findDOMNode在React严格模式下会触发警告,更推荐用ref来获取DOM元素:

// 在组件中创建ref
private containerRef = React.createRef<HTMLElement>();

// 在render中绑定ref
render() {
  return <div ref={this.containerRef}>{/* 你的内容 */}</div>;
}

// 在drags中使用ref获取元素
private drags() {
  const e = this.containerRef.current;
  if (e) {
    // ...添加监听器的逻辑
  }
}

这样的写法更符合React的设计理念,也更可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:41:51