reactjstypescriptreact-routerloadernested-routes

How do I use the loader feature from react-router v6.4 on the route's element?


I upgraded to react-router-dom@6.4 and I want to use the loader prop.

My router looks like this:

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route>
      <Route path="/" element={<PublicRoute />}>
        <Route path="/" element={<Login />} />
      </Route>
      <Route path="/home" element={<PrivateRoute />}>
        <Route path="/home" element={<Home />}>
          <Route path="dashboard/*" element={<DashboardRoutes />} />
          <Route path="projectSettings/*" element={<ProjectSettingsRoutes />} />
          <Route path="settings/*" element={<SettingsRoutes />} />
          <Route path="testDevelopment/*" element={<TestDevelopmentRoutes />} />
          <Route index element={<Navigate to={'dashboard'} replace />} />
        </Route>
      </Route>
    </Route>,
  ),
);

type props = {
  instance: PublicClientApplication;
};

const Router: FC<props> = ({ instance }) => {
  return (
    <MsalProvider instance={instance}>
      <RouterProvider router={router} />
    </MsalProvider>
  );
};

As you can see these routes render elements that also route. For example I want to use the loader for fetching elements on the UiElements component that is under TestDevelopment, so the element TestDevelopmentRoutes looks like this:

const TestDevelopmentRoutes = () => {
  return (
    <Routes>
      <Route path="" element={<TestDevelopment />}>
        <Route path="customFunctions" element={<CustomFunctions />} />
        <Route path="requirements" element={<Requirements />} />
        <Route path="runResults" element={<RunResults />} />
        <Route path="testCases" element={<TestCases />}>
          <Route path="table" element={<TestCasesTable />} />
        </Route>
        <Route index element={<Navigate to={'testCases'} replace />} />
        <Route path="testPlans" element={<TestPlans />} />
        <Route path="testSuites" element={<TestSuites />} />
        <Route path="uiElements" element={<UiElements />} loader={uiElementsLoader} />
        <Route path="uploads" element={<Uploads />} />
      </Route>
    </Routes>
  );
};

The fetch isn't happening because I can't use Routes anymore to enable the loader feature, but I can't figure out how I should right the routes on TestDevelopmentRoutes so it will work.


Solution

  • The loaders necessarily need to be passed at-the-time when creating the Data Router. It's because at compile/transpile-time the new Data Router can't possibly know what descendent routes it will be rendering at run-time. All the "test developement" routes would need to be moved into the configuration.

    const router = createBrowserRouter(
      createRoutesFromElements(
        <Route>
          <Route element={<PublicRoute />}>
            <Route path="/" element={<Login />} />
          </Route>
          <Route element={<PrivateRoute />}>
            <Route path="/home" element={<Home />}>
              <Route path="dashboard/*" element={<DashboardRoutes />} />
              <Route path="projectSettings/*" element={<ProjectSettingsRoutes />} />
              <Route path="settings/*" element={<SettingsRoutes />} />
    
              <Route path="testDevelopment" element={<TestDevelopment />}>
                <Route index element={<Navigate to="testCases" replace />} />
                <Route path="customFunctions" element={<CustomFunctions />} />
                <Route path="requirements" element={<Requirements />} />
                <Route path="runResults" element={<RunResults />} />
                <Route path="testCases" element={<TestCases />}>
                  <Route path="table" element={<TestCasesTable />} />
                </Route>
                <Route path="testPlans" element={<TestPlans />} />
                <Route path="testSuites" element={<TestSuites />} />
                <Route
                  path="uiElements"
                  element={<UiElements />}
                  loader={uiElementsLoader}
                />
                <Route path="uploads" element={<Uploads />} />
              </Route>
    
              <Route index element={<Navigate to={'dashboard'} replace />} />
            </Route>
          </Route>
        </Route>,
      ),
    );
    

    ...

    type props = {
      instance: PublicClientApplication;
    };
    
    const Router: FC<props> = ({ instance }) => {
      return (
        <MsalProvider instance={instance}>
          <RouterProvider router={router} />
        </MsalProvider>
      );
    };