首页 > 解决方案 > 如何将 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);
  };

标签: javascriptreactjsstatereact-lifecycleremoveeventlistener

解决方案


你需要两个useEffect:

  1. 这将创建一个监听器一次:

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

  2. 然后当 isOpen[1] 为假时,另一个将删除它:

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


推荐阅读