react-router icon indicating copy to clipboard operation
react-router copied to clipboard

[Feature]: Global loader callbacks

Open macjuul opened this issue 3 years ago • 1 comments

What is the new or updated feature that you are suggesting?

I would like to display a progress bar at the top of the page as the loaders are fetching data. I was planning on achieving this visually using Mantine navigation progress, however I can't seem to find a good way of calling the start and stop progress functions.

It would be extremely useful if we can use some sort of beforeLoaders and afterLoaders callbacks on a global level.

Optionally, this could also allow global level authentication guarding (redirect to sign in page) if we can return redirect('/signin') from these callbacks, similar to loaders.

Why should this feature be included?

This feature would allow global callbacks to trigger before loaders start and after loaders complete, allowing the display of visual hints to the user such as a progress bar.

macjuul avatar Sep 16 '22 09:09 macjuul

Use the useNavigation hook at your top-level route. This will give you the state of all loaders/actions in your app.

https://reactrouter.com/en/main/hooks/use-navigation

kiliman avatar Sep 16 '22 16:09 kiliman

Use the useNavigation hook at your top-level route. This will give you the state of all loaders/actions in your app.

https://reactrouter.com/en/main/hooks/use-navigation

Just tried to use the useNavigation hook together with react-top-loading-bar, but navigating using Link doesn't cause the navigation.state to change. It remains idle all the time.

tsabolov avatar Dec 13 '22 12:12 tsabolov

Same comment here. I don't get how to retrieve le loading state on the Root route.

With this simple configuration:

const router = createBrowserRouter([
    {
      path: "/",
      element: <Root />,
      children: [
        {
          path: "programme/:slug",
          element: <Programme />,
          loader: (args) => programmeLoader({ ...args }, apolloClient),
        },
      ],
    },
  ]);
// Root.tsx

export default function Root() {
  const navigation = useNavigation();
  console.log(navigation);

  return (
      <Outlet />
  );
}

When logging navigation to the console, everything is undefined and state is always idle. I guess that's me not using it properly, but that's not clear ;-)

// console.log(navigation)
{state: 'idle', location: undefined, formMethod: undefined, formAction: undefined, ...}

Note that I get exactly the same log from inside the <Programme /> component. State keeping on "idle" value is one thing, but having "location" undefined seems really odd!

One precision: we load directly a /programme/:slug URL in the browser. We don't "navigate" to it from a link. But still...

benjamindulau avatar Dec 20 '22 09:12 benjamindulau

useNavigation.state is the correct way to detect loading during a client side navigation. If you need to show a loading state during initialization of your SPA (the very first batch of loaders), then you would use the RouterPRovider fallbackElement prop.

Just tried to use the useNavigation hook together with react-top-loading-bar, but navigating using Link doesn't cause the navigation.state to change. It remains idle all the time.

My hunch here is that your loaders are synchronous, and if you never have to actually do anything async during your loaders, then the entire navigation is synchronous and it won't ever go into a loading state. In this case, I'd recommend looking at a change in useLocation().key.

I think that covers the use cases here so I'm going to close this out. If you need more beyond this, I think the Events Proposal is likely of interest, so go give that an upvote!

brophdawg11 avatar Jan 09 '23 22:01 brophdawg11