【问题标题】:Using a higher order component to add event listeners per component使用高阶组件为每个组件添加事件监听器
【发布时间】:2018-12-12 05:58:00
【问题描述】:

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

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 事件处理程序?

【问题讨论】:

    标签: javascript reactjs keydown higher-order-components recompose


    【解决方案1】:

    首先,请注意您的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的更多信息

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-13
      • 2015-07-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多