Как мне сделать окно removeEventListener используя React useEffect - PullRequest
2 голосов
/ 26 марта 2019

В документах React Hooks показано, как удалитьEventListener на этапе очистки компонента. https://reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect

В моем случае использования я пытаюсь удалить функцию EventListener, относящуюся к свойству состояния функционального компонента.

Вот пример, где компонент никогда не отключается, но слушатель события должен быть удален:

function App () {
  const [collapsed, setCollapsed] = React.useState(true);
  React.useEffect(
    () => {
      if (collapsed) {
        window.removeEventListener('keyup', handleKeyUp); // Not the same "handleKeyUp" :(
      } else {
        window.addEventListener('keyup', handleKeyUp);
      }
    },
    [collapsed]
  );
  function handleKeyUp(event) {
    console.log(event.key);
    switch (event.key) {
      case 'Escape':
        setCollapsed(true);
        break;
    }
  }

  return collapsed ? (
    <a href="javascript:;" onClick={()=>setCollapsed(false)}>Search</a>
  ) : (
    <span>
      <input placeholder="Search" autoFocus />&nbsp;
      <a href="javascript:;">This</a>&nbsp;
      <a href="javascript:;">That</a>&nbsp;
      <input placeholder="Refinement" />
    </span>
  );
}
ReactDOM.render(<App />, document.body.appendChild(document.createElement('div')));

(Живой образец в https://codepen.io/caqu/pen/xBeBMN)

Проблема, которую я вижу, заключается в том, что ссылка handleKeyUp внутри removeEventListener меняется каждый раз, когда компонент рендерится. Функция handleKeyUp нуждается в ссылке на setCollapsed, поэтому она должна быть заключена в App. Перемещение handleKeyUp внутри useEffect также, кажется, срабатывает несколько раз и теряет ссылку на оригинал handleKeyUp.

Как можно условно window.removeEventListener использовать React Hooks без размонтирования компонента?

1 Ответ

3 голосов
/ 26 марта 2019

Вы можете поместить функцию handleKeyUp внутри функции, заданной для useEffect, и только добавить слушателя и вернуть функцию очистки, когда collapsed имеет значение false.

useEffect(() => {
  if (!collapsed) {
    function handleKeyUp(event) {
      switch (event.key) {
        case "Escape":
          setCollapsed(true);
          break;
      }
    }

    window.addEventListener("keyup", handleKeyUp);
    return () => window.removeEventListener("keyup", handleKeyUp);
  }
}, [collapsed]);
...