React中removeEventListener未触发:点击后状态异常求助
问题分析与解决方案
嘿,我一眼就看出问题啦——这是bind()方法的常见坑!
为什么会出现多次触发hide()的情况?
每次调用this.hide.bind(this)都会返回一个全新的函数实例。也就是说:
- 你在
show()里绑定的监听函数,和hide()里试图移除的函数,根本不是同一个对象 - 所以
removeEventListener完全找不到要移除的那个监听,导致每次调用show()都会给document多绑一个hide() - 第三次点击时,document上已经绑定了2个
hide()监听,所以会触发两次,把listVisible又改成了false
怎么修复?
我们只需要确保addEventListener和removeEventListener使用同一个函数引用就行,有几种简单的方式:
方案1:在构造函数里提前绑定方法
这是类组件里最常用的方式,在组件初始化时就把hide方法的this绑定好,全程用同一个引用:
constructor(props) { super(props); this.state = { listVisible: false, selected: props.selected || {} // 根据你的实际初始状态调整 }; // 关键:提前绑定hide方法,确保整个组件生命周期里引用唯一 this.hide = this.hide.bind(this); } show() { console.log("SHOW FUNCTION"); this.setState({ listVisible: true }); // 直接用提前绑定好的this.hide,不用再bind document.addEventListener("click", this.hide); } hide() { console.log("HIDE FUNCTION"); this.setState({ listVisible: false }); // 移除的是同一个函数引用,这次就能生效了 document.removeEventListener("click", this.hide); }
方案2:用箭头函数定义类方法(需要开启类字段语法)
如果你用的是支持类字段的编译环境(比如Create React App默认支持),可以直接把hide定义成箭头函数,自动绑定this,而且引用固定:
// 直接用箭头函数定义,自动绑定this hide = () => { console.log("HIDE FUNCTION"); this.setState({ listVisible: false }); document.removeEventListener("click", this.hide); } show() { console.log("SHOW FUNCTION"); this.setState({ listVisible: true }); document.addEventListener("click", this.hide); }
额外优化:阻止事件冒泡避免误触发
另外还有个小问题:当你点击dropdown-display触发show()时,这个点击事件会冒泡到document,而你刚给document绑定了hide(),可能会立刻触发它导致状态来回切换。所以要在点击事件里阻止冒泡:
// 修改render里的dropdown-display的onClick <div className={"dropdown-display" + (this.state.listVisible ? " clicked": "")} onClick={(e) => { e.stopPropagation(); // 阻止事件冒泡到document this.show(); }}>
内存泄漏防护
最后,别忘了在组件卸载时移除监听,防止内存泄漏:
componentWillUnmount() { document.removeEventListener("click", this.hide); }
这样修改后,你就能正常控制listVisible的状态,不会出现多次触发hide()的问题啦!
内容的提问来源于stack exchange,提问作者Filth
相关产品推荐
相关产品推荐

