reactjsnon-exhaustive-patterns

exhaustive-deps infinite loop with function dependant on component state


Given the following example

const SettingsLayout = () => {
  const [tabs, setTabs] = useState(SettingsNavigation);
  const router = useRouter();

  const updateActiveTab = useCallback(
    (pathname) => {
      setTabs(
        tabs.map((tab: Tab) => ({
          ...tab,
          current: tab.href === pathname,
        }))
      );
    },
    [tabs]
  );

  useEffect(() => {
    updateActiveTab(router.pathname);
  }, [router.pathname]);
  // exhaustive-deps wants me to add updateActiveTab to the dependency array
  // but adding it will cause an infinite render loop
  // Flux:
  //   -> useEffect will change tabs
  //   -> tabs will change updateActiveTab
  //   -> updateActiveTab will execute useEffect

  return (...)
}

So far i have not found a solution other than disabling exhaustive-deps, i've read you shouldn't do it.

How can i execute updateActiveTab only when router.pathname changes?


Solution

  • Check this out!

    const SettingsLayout = () => {
      const allTabs = SettingsNavigation;
      const [tabs, setTabs] = useState();
      const router = useRouter();
    
      const updateActiveTab = useCallback(
        (pathname) => {
          setTabs(
            allTabs.map((tab: Tab) => ({
              ...tab,
              current: tab.href === pathname,
            }))
          );
        },
        [allTabs]
      );
    
      useEffect(() => {
        updateActiveTab(router.pathname);
      }, [router.pathname]);
    
      return (...)
    }