Прослушиватель событий React keydown вызывается несколько раз?

#reactjs

#reactjs

Вопрос:

Итак, я сделал этот модальный https://codesandbox.io/s/amazing-morning-ukxp2?file=/src/components/Modal.js

Всякий раз, когда вы нажимаете клавишу esc, предполагается, что она закрывает модальный. Я добавил сообщение, которое будет отображаться при каждом нажатии esc.

Но если вы проверите консоль, она каждый раз печатает мои сообщения, кратные 2 раза, поэтому через некоторое время оно будет повторять сообщение примерно 100 раз

Это функция, на которую я ссылаюсь

            function keyPress(e) {
        if (e.key === 'Escape' amp;amp; showModal) {
          setShowModal(false);
          console.log('I pressed');
        }
      }

      document.addEventListener('keydown', keyPress);
  

Я попытался поместить его в функцию useEffect и добавить ShowModal в качестве зависимости, но я не смог заставить его работать должным образом

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

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

Ответ №1:

Вам необходимо обрабатывать прослушиватели событий (добавлять, удалять) внутри useEffect hook:

 useEffect(() => {
  document.addEventListener("keydown", keyPress);
  return () => document.removeEventListener("keydown", keyPress);
});
  

Таким образом, вы будете подписываться на keyPress функцию в каждом жизненном цикле.
Чтобы улучшить его еще больше, вы могли бы обернуть keyPress в useCallback hook (для запоминания функции в новых рендерах) и добавить ее в качестве зависимости:

   const keyPress = useCallback(
    (e) => {
      if (e.key === "Escape" amp;amp; showModal) {
        setShowModal(false);
        console.log("I pressed");
      }
    },
    [setShowModal, showModal]
  );

  useEffect(() => {
    document.addEventListener("keydown", keyPress);
    return () => document.removeEventListener("keydown", keyPress);
  }, [keyPress]);
  

Модифицированный codesandbox

Комментарии:

1. когда мне нужно беспокоиться о добавлении массива в качестве зависимости? или почему вам не нужно было добавлять его в этом примере?

2. Вы правы, это простое изменение приведет к подписке на каждый жизненный цикл. Я добавил, как добавить вашу функцию в качестве зависимости и запомнить ее, чтобы не создавать ее при каждом повторном рендеринге.

Ответ №2:

  useEffect(()=>{
        document.addEventListener('keydown', someFunction); 
    }, []);
  

пустой массив в конце будет реагировать до тех пор, пока не будет обновлен компонент после загрузки