Geoff
Geoff

Reputation: 6639

React router route loader not working on nested components

Am using react router v6 and i would like to use the new loader to load the data before the component loads. So i have the following

In my index.js

const router = createBrowserRouter(
createRoutesFromElements(
    <Route path="*"
           loader={async ({ params }) => {

               console.log("index loader log"); //this logs

               return true;
           }}
           element={<App />}
     > </Route>
  )
);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <RouterProvider router={router} />
);

in my app component i have nested routes like

const App = () => {
 return (
     <>
        <Routes>
            <Route path="auth/*" element={<AuthLayout/>}/>
            <Route path="about"
             loader={async ({ params }) => {

               console.log("about child loader log"); //this doesnt log

               return true;
              }}
           element={<AboutPage/>}/>
        </Routes>
        <h1>Testing app</h1>
     </>

   );

 }

On the app component the loader on the Route path="about" does not console.log when i visit the about route but the component is rendered. What am i missing for the loader to work on the child route.

Upvotes: 8

Views: 9252

Answers (1)

Drew Reese
Drew Reese

Reputation: 202751

Based on some basic testing it seems that in order for the new RRDv6.4 data APIs to work you need to specify the complete routing configuration in the createBrowserRouter function.

There does however appear to already be an issue filed with @remix-run/react-router for this behavior as a reported bug, so you may want to follow it if it ever addressed/resolved. (I suspect it was you since the name is "geoffrey" and the timing is coincidentally about an hour ago around the same time as this post)

This above issue has since been closed with comment:

Descendant <Routes> trees do not participate in data loading (https://reactrouter.com/en/main/components/routes) since they cannot be known ahead of render-time. You'll need to lift your descendant route definitions up into the routes you pass to createBrowserRouter.

The relevant information regarding the descendent routes and the new Data API can be found in the Routes documentation in a note.

Note:

If you're using a data router like createBrowserRouter it is uncommon to use this component as it does not participate in data loading.

Hoist the entire route declaration to the parent creating the data router. The following does work with the loader function for the "/about" route and About component.

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route
      path="*"
      loader={({ params }) => {
        console.log("index loader log");

        return "This is the App";
      }}
      element={<App />}
    >
      <Route path="auth/*" element={<AuthLayout />} />
      <Route
        path="about"
        loader={({ params }) => {
          console.log("about child loader log");

          return "this is the about page";
        }}
        element={<AboutPage />}
      />
    </Route>
  )
);

The App component should render an Outlet for the nested routes to render their content into.

import { Outlet } from 'react-router-dom';

const App = () => {
  return (
    <>
      <h1>Testing app</h1>
      <Outlet />
    </>
  );
};

Edit react-router-route-loader-not-working-on-nested-components

enter image description here

Upvotes: 10

Related Questions