Search code examples
react-router-dom

default page with Navigate vs default page with index route


Library version: react-router-dom v6

I am not very clear on the difference between using a <Navigate/> element to implement a default route versus using an index route for the same purpose. Which of the following is more idiomatic?

The duplication of the call to the <Clients/> component in B bothers me a bit but I don't see a way around it if the default path we wish to use coincides with an actual path (as is more often than not the case).

A. using Navigate to implement a default view

export const router = createBrowserRouter([
  {
    path: '/',
    element: <Navigate to='/clients' replace={true} />,
    errorElement: <ErrorPage/>,
  },
  {
    path: '/',
    element: <RootLayout/>,
    children: [
      {
        path: 'clients',
        element: <Clients/>
      },
      {
        path: 'contracts',
        element: <Contracts/>
      }
    ]
  },
]);

B. using an index route to implement a default view

export const router = createBrowserRouter([
  {
    path: '/',
    element: <RootLayout/>,
    children: [
      {
        index: true,
        element: <Clients/>
      },
      {
        path: 'clients',
        element: <Clients/>
      },
      {
        path: 'contracts',
        element: <Contracts/>
      }
    ]
  },
]);

Solution

  • I'd say the idiomatic method of specifying/redirecting to a default page is Option C, an index route that redirects to the default route.

    Example:

    export const router = createBrowserRouter([
      {
        path: '/',
        element: <RootLayout />,
        children: [
          {
            index: true,
            element: <Navigate to="clients" replace />
          },
          {
            path: 'clients',
            element: <Clients />
          },
          {
            path: 'contracts',
            element: <Contracts />
          }
        ]
      },
    ]);
    

    Option A is incorrect because it renders two routes for the same "/" path, and Option B is W.E.T. since it declares two routes that render the same component (honestly not the worst thing in the world since RRD is "smart" enough to keep instances of these components mounted when navigating between routes that render them).

    Layout routes also don't need explicit paths, so the following would also work:

    export const router = createBrowserRouter([
      {
        element: <RootLayout />,
        children: [
          {
            path: '/', // or `index: true,` but not both
            element: <Navigate to="clients" replace />
          },
          {
            path: 'clients',
            element: <Clients />
          },
          {
            path: 'contracts',
            element: <Contracts />
          }
        ]
      },
    ]);
    

    The root RootLayout layout route simply wraps the nested routes, and the root/home "/" renders the redirect to the default page.