首页 > 解决方案 > 当组件在反应中卸载时消除功能的副作用?

问题描述

我正在开发一个 react-app 并使用以下功能来跟踪我的导航面板中的活动链接。

以下函数用于IntersectionObserver跟踪给定元素是否在视口中。

该代码能够解决其动机。
但是当我将路由更改为不同的组件时,它会显示错误 -TypeError: Cannot read property 'parentElement' of null

那是因为使用该功能的组件changeActiveLink();不再在页面中(它已被卸载)。

我想在移除组件时移除此功能的效果。

我尝试将它与该事件侦听器集成DOMContentLoaded eventListener,然后清理该事件侦听器,但该事件侦听器仅适用于 HTML 文档的第一次渲染,并且当我们在所需路由上渲染组件而使函数changeActiveLink();未初始化时不起作用。

我应该如何让这个功能只在这个特定的组件中工作,并避免它对其他组件的影响?

错误画面截图

useEffect(() => {
    const changeActiveLink = () => {
      
      const scrollHandler = (entries) => {
        entries.forEach((entry) => {
          const id = entry.target.getAttribute("id");

          if (entry.intersectionRatio > 0) {
            document
              .querySelector(`nav li a[href="#${id}"]`)
              .parentElement.classList.add("active");
          } else {
            document
              .querySelector(`nav li a[href="#${id}"]`)
              .parentElement.classList.remove("active");
          }
        });
      };

      const observer = new IntersectionObserver(scrollHandler);

      // Track all sections that have an `id` applied
      document.querySelectorAll("section[id]").forEach((section) => {
        observer.observe(section);
      });
    };

    changeActiveLink();
    
  }, []);

标签: javascripthtmlreactjsreact-routerreact-hooks

解决方案


返回一个不观察目标元素的useEffect 清理函数

useEffect(() => {
  const changeActiveLink = () => {

    const scrollHandler = (entries) => {
      entries.forEach((entry) => {
        const id = entry.target.getAttribute("id");

        if (entry.intersectionRatio > 0) {
          document
            .querySelector(`nav li a[href="#${id}"]`)
            .parentElement.classList.add("active");
        } else {
          document
            .querySelector(`nav li a[href="#${id}"]`)
            .parentElement.classList.remove("active");
        }
      });
    };

    const observer = new IntersectionObserver(scrollHandler);

    const sections = document.querySelectorAll("section[id]");

    // Track all sections that have an `id` applied
    sections.forEach((section) => {
      observer.observe(section);
    });
    
    return () => {
      // untrack all sections that have an `id` applied
      sections.forEach((section) => {
        observer.unobserve(section);
      });
    }; // return the cleanup function
  };

  return changeActiveLink(); // you should also return the function here

}, []);

推荐阅读