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

时间:2018-07-03 20:57:42

标签: 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))
    },
    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

     

组件2的嗨

另一方面,一旦其中一个组件被卸载,我将不再有任何事件。

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

1 个答案:

答案 0 :(得分:3)

首先,请您注意您的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;

然后

// somewhere-else.js

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

有关如何结帐this answer

的更多信息