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
相关产品推荐
相关产品推荐

