0

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?

HYAR7E
  • 194
  • 2
  • 10

1 Answers1

1

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 (...)
}
  • Thank you very much! this works just fine, but what would happen if i need to use the current state `tabs` in `updateActiveTab`? would using useRef to make a copy be fine? – HYAR7E Mar 30 '22 at 04:57
  • You should not be using `tabs` in a same function body where you are also using `setTabs` that's gonna break due to infinite loop, but if you need to compare and merge the old state with new state you also do so like this `setTabs((oldTabs)=> oldTabs.map((tab: Tab) => ({ ...tab, current: tab.href === pathname, })) );` but in my opinion that would not suite in your case as you just want to have one tab active at the moment not the all which were before due to pathname change. – Ali Hussnain - alichampion Mar 30 '22 at 06:52