React Hooks: Как очистить слушателей событий? - PullRequest
0 голосов
/ 26 апреля 2020

У меня есть компонент Example, в котором я хочу очистить прослушиватель событий , когда локальное состояние display меняется на false , display установлено на true когда show prop = true и наоборот.

Код:

const Example = ({ show, onClose }) => {
  const [display, setDisplay] = useState(false);

  const handleClick = (e) => {
    onClose();
    console.log(display);
  };

  useEffect(() => {
    if (display) {
      document.addEventListener('click', handleClick);
    } else {
      document.removeEventListener('click', handleClick);
    }
  }, [display, handleClick]);

  useEffect(() => {
    if (show) {
      setDisplay(show);
    } else {
      setDisplay(false);
    }
  }, [show]);

  return <div>{display && <p>Hi</p>}</div>;
};

Проблемы:

  • Компонент не может очистить прослушиватель событий, поскольку новая ссылка функции handleClick() создается каждый раз, когда Example отображает .
  • Каждый раз, когда вызывается handleClick(), он регистрирует display как true .
  • После 7-8 щелчков мыши , журнал количество в консоли достигает 7-8K .

Что я здесь не так делаю? Спасибо:)

1 Ответ

0 голосов
/ 26 апреля 2020

Чтобы очистить в useEffect, верните функцию в эффекте. Эта функция будет вызываться при каждом повторном запуске эффекта и при размонтировании компонента.

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

useEffect(() => {
  if (!display) {
    return;
  }

  document.addEventListener('click', handleClick);

  return () => document.removeEventListener('click', handleClick);
}, [display, handleClick]);

Кроме того, вы можете сделать эффект менее частым, используя вместо этого ссылку на функцию handleClick.

Например, в большинстве случаев это c. Хотя вы можете легко абстрагировать некоторые ссылки и дополнительный эффект использования на отдельный хук.

const handleClickRef = useRef(handleClick);

useEffect(()=>{
  handleClickRef.current = handleClick;
},[handleClick])

useEffect(() => {
  if (!display) {
    return;
  }
  const funct = (evt)=>handleClickRef.current(evt);
  document.addEventListener('click',funct);

  return () => document.removeEventListener('click', funct);
}, [display]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...