Javascript 使用高阶组件为每个组件添加事件侦听器

Javascript 使用高阶组件为每个组件添加事件侦听器,javascript,reactjs,keydown,higher-order-components,recompose,Javascript,Reactjs,Keydown,Higher Order Components,Recompose,我的应用程序中有一些组件,可以处理来自键盘的一些用户输入。为此,我创建了以下函数: export default function withKeydownEventHandler (handler) { id = id + 1 return lifecycle({ componentWillMount () { $(window).on(`keydown.${id}`, evt => handler(evt)) }, componentWillU

我的应用程序中有一些组件,可以处理来自键盘的一些用户输入。为此,我创建了以下函数:

export default function withKeydownEventHandler (handler) {
  id = id + 1
  return lifecycle({
    componentWillMount () {
      $(window).on(`keydown.${id}`, evt => handler(evt))
    },
    componentWillUnmount () {
      $(window).off(`keydown.${id}`)
    }
  })
}
这可以很好地工作,但是同时为不同的组件启动处理程序。因此,如果我的处理程序在每个组件中执行不同的操作,每当我单击一个按钮时,它将同时从两个组件中触发。此外,一旦卸载了一个组件,HoC将不再工作

例如,假设我有以下两个容器:

export default compose(
  withKeydownEventHandler((evt, props) => {
    console.warn('hi from Component 1')
  }),
  withProps(() => {
    // stuff
  })
)(Component1)

export default compose(
  withKeydownEventHandler((evt, props) => {
    console.warn('hi from Component 2')
  }),
  withProps(() => {
    // stuff
  })
)(Component2)
如果我在整个应用程序中单击任何按钮,我将获得以下输出:

来自组件1的hi

来自组件2的hi

另一方面,一旦其中一个组件被卸载,我就不再得到任何事件


我做错了什么?如何通过一个可以在整个应用程序中重复使用的HoC获取按键事件处理程序?

首先,请注意,您的
id
设置为全局变量。是否确实要将此变量名作为全局变量

其次,您正在使用
$(window.on('keydown.${id}',evt=>handler(evt))
将keydown事件绑定到窗口,这解释了您不想要的行为。您需要将它与希望处理程序执行操作的特定组件绑定一次

最后,为什么不创建一个HOC类并有条件地添加事件侦听器呢?例如:

// src/Hoc.jsx

export default function(WrapperComponent) {
  return class extends Component {
    componentWillMount () {
      const { onKeyDownHandler } = this.props;
      if (isKeyDownEventNeeded) {
         this.comp.addEventListener("keydown", onKeyDownHandler);
      }
    }
    componentWillUnmount () {
      const { onKeyDownHandler } = this.props;
      if (isKeyDownEventNeeded) {
         this.comp.removeEventListener("keydown", onKeyDownHandler);
      }
    }
    render() {
        const { onKeyDownHandler } = this.props;
        if (onKeyDownHandler) { 
            // a "ref" callback which assigns the mounted 
            // Element to a prop "comp" whicu can be used later to add the DOM listener to.
            return <WrapperComponent ref={elem => this.comp = elem} {...this.props} />
        }
        return <WrapperComponent {...this.props} />
    }
}

export default HighOrderComponent;
//src/Hoc.jsx
导出默认函数(包装器组件){
返回类扩展组件{
组件将安装(){
const{onKeyDownHandler}=this.props;
如果(IsKeyDownEventRequired){
此.comp.addEventListener(“keydown”,onKeyDownHandler);
}
}
组件将卸载(){
const{onKeyDownHandler}=this.props;
如果(IsKeyDownEventRequired){
此.comp.removeEventListener(“keydown”,onKeyDownHandler);
}
}
render(){
const{onKeyDownHandler}=this.props;
if(onKeyDownHandler){
//一个“ref”回调,用于分配已装入的
//元素添加到prop“comp”中,以后可以使用它将DOM侦听器添加到。
返回this.comp=elem}{…this.props}/>
}
返回
}
}
导出默认的HighOrderComponent;
然后

//where-else.js
从“src/Hoc”导入highOrderComponent
highOrderComponent(console.log('hey,Component 1')/>
highOrderComponent(console.log('hey,Component 2'}/>
如需有关如何退出的更多信息,请查看

// somewhere-else.js

import highOrderComponent from 'src/Hoc'    
highOrderComponent(<Component1 onKeyDownHandler={() => console.log('hey, Component 1'} />
highOrderComponent(<Component2 onKeyDownHandler={() => console.log('hey, Component 2'} />