Как я могу синхронизировать removeEventListener с состоянием компонента?

извините за запутанный код. Я действительно запуталась здесь.

У меня есть Nav компонент, который я хочу скрыть, когда пользователь прокручивает. Прокрутка обнаруживается с помощью прослушивателя событий (который сейчас находится в useEffect, я действительно не знаю почему), который вызывает scrollDetect().

scrollDetect затем устанавливает переменную состояния scrollState, которая подключается к CSS через стилизованные компоненты.

Все работает очень хорошо, за исключением того, что я хочу остановить прослушиватель событий, когда панель навигации открыта. Открытое состояние панели навигации хранится в isOpen[1], но оно просто не обновляется в правильном порядке. Когда панель навигации открыта, кнопки по-прежнему прячутся при прокрутке. Чтобы увидеть поведение, о котором я говорю, посетите erasebegin.net. Попробуйте нажать одну из кнопок меню и затем прокрутить окно.

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

export default function Nav() {
  const [isOpen, setIsOpen] = useState(["", false]);
  const [envOpen, setEnvOpen] = useState(false);
  const [scrollState, setScrollState] = useState("show");

  // HIDE NAVBUTTONS ON DOWN SCROLL, REVEAL ON UP SCROLL

  var lastScrollTop = window.pageYOffset || window.scrollTop;

  const scrollDetect = () => {
    if (isOpen[1] === false) {
      var st = window.pageYOffset || document.documentElement.scrollTop;
      if (st < lastScrollTop) {
        setScrollState("show");
      } else if (st > lastScrollTop) {
        setScrollState("hide");
      }
      lastScrollTop = st <= 0 ? 0 : st;
    }
  };

  useEffect(() => {
    console.log(isOpen[1]);
    const listener = document.addEventListener("scroll", scrollDetect);
    const cleanup = () => {
      document.removeEventListener("scroll", listener);
      return cleanup;
    };
  }, [isOpen[1]]);

  const setOpen = ([title, state]) => {
    let newState = !state;
    setIsOpen([title, newState]);
  };

  const envelopeOpen = () => {
    setEnvOpen(true);
  };

  const envelopeClose = () => {
    setEnvOpen(false);
  };

person Chris Haupt    schedule 11.08.2020    source источник
comment
Может ли кто-нибудь помочь. Это кажется невозможным. removeEventListener определенно запускается, но ничего не происходит T_T прослушиватель событий остается на месте   -  person Chris Haupt    schedule 12.08.2020


Ответы (2)


Вы неправильно удаляете прослушиватель событий. Попробуйте следующее:

useEffect(() => {
    if (isOpen[1]) {
       document.addEventListener("scroll", scrollDetect);
    } else {
      document.removeEventListener("scroll", scrollDetect);
    }

    return () => document.removeEventListener("scroll", scrollDetect);
  }, [isOpen]);

person jank    schedule 11.08.2020
comment
Спасибо за ответ :) К сожалению, это не работает. Когда я регистрирую состояние isOpen[1] в useEffect, он показывает правильное состояние, но прослушиватель событий, кажется, все еще активен, даже когда isOpen[1] _4 _... `` `useEffect (() =› {console.log (isOpen [1 ]) if (isOpen [1] === false) {document.addEventListener (scroll, scrollDetect);} else {document.removeEventListener (scroll, scrollDetect);}}, [isOpen [1]]); `` '' - person Chris Haupt; 11.08.2020
comment
Что ж, это ожидается из приведенного выше кода, не так ли? Это просто пример того, как правильно добавлять и удалять слушателей :) - person jank; 11.08.2020
comment
Это не то, чего я ожидал. Я ожидаю, что прослушиватель событий будет удален, когда isOpen [1] истинно, и возобновится, когда isOpen [1] имеет значение false. Это кажется очень простым делом, но ничего из того, что я пробовал, не помогло! - person Chris Haupt; 12.08.2020

Вам нужно два useEffect:

  1. Это создаст слушателя один раз:

    useEffect (() = ›{document.addEventListener (scroll, scrollDetect);}, []);

  2. Затем другой удалит его, когда isOpen [1] будет ложным:

    useEffect (() = ›{if (! isOpen [1]) {document.removeEventListener (scroll, scrollDetect);}}, [isOpen]);

person Abdul    schedule 11.08.2020
comment
Спасибо, Абдул, но опять же, это не сработало. Когда я регистрирую isOpen[1] во втором useEffect, он получает правильный сигнал в нужное время, но прослушиватель событий остается активным! - person Chris Haupt; 12.08.2020
comment
Можете ли вы поделиться последним кодом после внесения предложенных мной изменений? - person Abdul; 13.08.2020