Использование компонента более высокого порядка для добавления прослушивателей событий для каждого компонента - PullRequest
0 голосов
/ 03 июля 2018

В моем приложении есть некоторые компоненты, которые должны обрабатывать некоторые пользовательские вводы с клавиатуры. Для этого я создал следующую функцию:

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

С другой стороны, когда один из компонентов отключается, я больше не получаю никаких событий.

Что я делаю не так? Как я могу получить обработчик события keydown через HoC, который можно повторно использовать в моем приложении?

1 Ответ

0 голосов
/ 04 июля 2018

Во-первых, могу ли я обратить ваше внимание, что ваш id задан как глобальная переменная. Вы уверены, что хотите иметь такое имя переменной, как глобальное?

Во-вторых, вы связываете событие keydown с окнами с помощью $(window).on('keydown.${id}', evt => handler(evt)), которое объясняет ваше нежелательное поведение. Вам нужно связать его один раз с конкретным компонентом, с которым должен работать обработчик.

Наконец, почему вы не создаете класс 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'} />

Для получения дополнительной информации о том, как проверить этот ответ

...