React组件keydown事件监听器回调触发两次问题求助
解决键盘事件触发两次的问题
核心原因及修复方案
1. 事件监听器未正确移除,导致重复绑定
你的代码在componentDidMount中添加了键盘事件监听,但未在组件卸载时移除。若组件被多次挂载(比如路由切换、React StrictMode开发环境),会绑定多个相同的监听器,每次按键就会触发多次回调。
修复步骤:
- 修改
componentDidMount,直接传递绑定好的handleKeyPress(不要用箭头函数包裹,确保添加和移除的是同一个函数引用):public componentDidMount () { global?.document.addEventListener('keydown', this.handleKeyPress); } - 添加
componentWillUnmount生命周期方法,移除事件监听:public componentWillUnmount() { global?.document.removeEventListener('keydown', this.handleKeyPress); }
2. React StrictMode 开发环境的重复挂载
在React严格模式下,开发环境会重复调用componentDidMount(用于检测副作用),这也会导致两次事件绑定。上述移除监听器的操作已经能解决这个问题——组件卸载时会清理监听器,第二次挂载时重新绑定一次即可。
3. 可选:阻止事件冒泡(按需使用)
如果页面中还有其他元素监听键盘事件,事件可能会通过冒泡触发多次回调,可以在回调中添加阻止冒泡的逻辑:
private handleKeyPress = (event: KeyboardEvent) => { event.stopPropagation(); // 阻止事件向上冒泡 // 原有逻辑... }
额外优化建议
- 在
scrollToSolutions中,先判断id是否有效再执行后续逻辑,避免无效操作:private scrollToSolutions = (id?: number) => { if (!id) return; const item = document.getElementById(id.toString()); this.setState({activeType: id}); item?.scrollIntoView({block: 'center'}); } - 在
handleKeyPress中,判断索引边界,防止超出数组范围:private handleKeyPress = (event: KeyboardEvent) => { const {activeType} = this.state; const {allSolutions} = this.props; const index = allSolutions.findIndex(x => x === activeType); if (event.key === 'ArrowDown') { const nextIndex = index + 1; if (nextIndex < allSolutions.length) { this.scrollToSolutions(allSolutions[nextIndex]); } } else if (event.key === 'ArrowUp') { const prevIndex = index - 1; if (prevIndex >= 0) { this.scrollToSolutions(allSolutions[prevIndex]); } } }
内容的提问来源于stack exchange,提问作者Fateme M
相关产品推荐
相关产品推荐

