2

I am new to React. I am making an app using AntD-mobile. For Bottom navigation, I am making use of the tabBar Component in AntD-mobile. I was not sure how to use Link for routing with TabBar and after a lot of failed attempts, came upon useNavigate.

const [navLink, setNavLink] = React.useState("/");
const navigate = useNavigate();
const redirect = useCallback(() => navigate(navLink, {replace: true}), [navigate]);

I want to redirect to whichever tab is clicked upon, for that, I used State, TabBar's onChange changes the state first and calls redirect. But for some reason, the previous state is loaded. If I am on state 1 and click 2, it stays on 1, When I click 4, it goes to 2 and so on. So probably, the redirect is loading ahead of state change. -

<TabBar onChange={(key)=>{setNavLink(key); redirect();}}>
      {tabs.map(item => (
            <TabBar.Item key={item.key} icon={item.icon} title={item.title}>
            </TabBar.Item>
      ))}
</TabBar>

To solve, this I tried using useEffect(), wherein I change only the state in TabBar's onChange and call redirect inside useEffect. But this doesn't work. redirect is not working.

useEffect(() => {
        redirect()
    }, [navLink]);

What am I doing wrong? How to set bottom navigation in the tabBar?

Parth Kapadia
  • 507
  • 6
  • 18
  • You did not provide any input for `navLink` variable. – SMAKSS Apr 06 '22 at 06:05
  • @SMAKSS, where? I didn't get the comment.. I initialized `navLink` with "/" and whenever the user clicks on any tab, its "key" which is the same as the route I want to specify is set using `setNavLink` – Parth Kapadia Apr 06 '22 at 06:16

1 Answers1

2

Issue

The original code didn't work because both setNavLink(key); and redirect(); happen in the same render cycle. When redirect is called the enqueued state update hasn't been processed yet, so it's still the previous state's value.

onChange={(key) => {
  setNavLink(key); // <-- enqueued state update
  redirect();      // <-- navLink state not updated yet!
}}

Solutions

The redirect function is missing a dependency, adding navLink to the dependency array will re-enclose the updated navLink state value. useCallback(() => navigate(navLink, {replace: true}), [navigate]); only computes/recomputes the callback on the initial render or when the dependencies update.

const redirect = useCallback(
  () => navigate(navLink, { replace: true }),
  [navigate, navLink]
);

useEffect(() => {
  redirect()
}, [redirect]);

...

onChange={setNavLink}

You can pass the navLink state in as an argument.

const redirect = useCallback(
  (navLink) => navigate(navLink, { replace: true }),
  [navigate]
);

useEffect(() => {
  redirect(navLink);
}, [navLink, redirect]);

...

onChange={setNavLink}

Or you can just use navigate directly in the useEffect when the navLink state updates.

useEffect(() => {
  navigate(navLink, { replace: true });
}, [navLink]);

...

onChange={setNavLink}

Or just navigate directly in the onChange handler.

<TabBar onChange={(navLink) => navigate(navLink, { replace: true })}>
  {tabs.map(item => (
    <TabBar.Item
      key={item.key}
      icon={item.icon}
      title={item.title}
    />
  ))}
</TabBar>
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • 1
    Works like a charm! Thanks. Why didn't my code work? redirect had a callback that used a state - `navLink`. Whenever navLink changes, shouldn't everything which uses it reload? – Parth Kapadia Apr 06 '22 at 10:27
  • @ParthKapadia The original code didn't work because both `setNavLink(key);` *and* `redirect();` happen in the same render cycle. When `redirect` is called the enqueued state update hasn't been processed yet, so it's still the previous state's value. – Drew Reese Apr 06 '22 at 15:14