28

I am trying react router v6. As per react training blog, I have created object of routing and passed to useRoutes():

function SomeOtherElement() {
  return <h1>add user</h1>;
}

const routes = [
  {
    path: 'app',
    element: <DashboardLayout />,
    children: [
      { path: 'account', element: <AccountView /> },
      {
        path: 'users', element: <UserListView />, 
        children: [
          { path: 'add', element: <SomeOtherElement /> }
        ]
      },
      { path: 'dashboard', element: <DashboardView /> },
      { path: 'products', element: <ProductListView /> },
      { path: 'settings', element: <SettingsView /> },
      { path: '*', element: <Navigate to="/404" /> }
    ]
  }];

const routing = useRoutes(routes);

But the nested routing is not working. As you can see in above object, I want to create URL and render the UI for user "add" functionality.

URL in the browser is getting updated correctly to http://localhost:3000/app/users/add but UI is not updating.

5 Answers 5

67

The default behavior of React Router fails to render multiple child routes with single Outlet. For example - When there is requirement to have a single Header in all the pages and replace the common content (Single Outlet) based on Route.

The trick here is to not provide any element attribute for parent but to provide this component as a child route with the help of Index attribute.

Index helps us to have a default component for a parent route if the child routes doesn't match any of the child routes.

The code snippet for this would be similar to the one provided by Samira.

<BrowserRouter>
  <Routes>
    <Route path="/" element={<App />}>
      <Route path="" element={<Home />}></Route>
      <Route path="child1"> //no element attribute here
        <Route index={true} element={<Child1 />}></Route>
        <Route path="grandChild1" element={<GrandChild1 />}></Route>
        <Route path="grandChild2" element={<GrandChild2 />}></Route>
      </Route>
    </Route>
  </Routes>
</BrowserRouter>
Sign up to request clarification or add additional context in comments.

6 Comments

Would this be considered an exploit? And does this work to even deeper hierarchies?
I don't think it should be considered exploit. And about the hierarchies, I have personally not tried on deeper levels, but yes if we have got the concepts correct, then it should work.
The index={true} fixed my issue (for anyone else who might stumble here with the same issue as me)
It would have been helpful to post what this looks like inside useRoutes([]) as objects in the array, and not markup. The question originally posed it like that. It is not difficult to translate but would speed it up for new people not understanding the difference between descendent and nested routes. (Tried to post it, but too ugly and unreadable in a comment)
Thank you, this solves the issue. Was using nextjs, switched to base react for a project and now I remember that I seldom hated the router.
|
34

As explained here, you need to use an <Outlet /> element as a placeholder for child i.e. nested routes.

Example:

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

// ... 

const routes = [
  {
    path: "app",
    element: (
      <>
        <DashboardLayout />
        <Outlet />
      </>
    ),
    children: [
      { path: "account", element: <AccountView /> },
      {
        path: "users",
        element: (
          <>
            <UserListView />
            <Outlet />
          </>
        ),
        children: [{ path: "add", element: <SomeOtherElement /> }],
      },
      { path: "dashboard", element: <DashboardView /> },
    ],
  },
];

Or you may want to have Outlet inside your parent components:

export default function DashboardLayout() {
  return (
    <>
      <h1>I am Dashboard Layout</h1>
      <Outlet />
    </>
  );
}

Comments

13

It is a helpful example for me because I wanted to use nested Route but I didn't want to use Outlet so I found it :

pay attention you can make a dynamic route with path=":teamId"

<BrowserRouter>
        <Routes>
          <Route path="/">
            <Route index={true} element={<Home />} />
          </Route>
          <Route path="/teams">
            <Route index={true} element={<ParentTeam />} />
            <Route index={false} path=":teamId" element={<Team />} />
            <Route index={false} path="new" element={<NewTeamForm />} />
          </Route>
          <Route path="*" element={<Home />} />
        </Routes>
   </BrowserRouter>

link to codeSandBox

6 Comments

What actually the index prop does?
the index determines the main page in a specific route
so the path of ParentTeam is "/teams"
Thanks @Samira. Saved me man.... No need to explicitly put index except if it IS the index. Again thanks....
You're welcome @MarkaA. I put the index in each route to have a better understanding.
|
5

For the useRoutes hook the syntax looks like this:

const items = [
  {
    path: "/login",
    element: <Login />,
  },
  {
    path: "/logout",
    element: <Logout />,
  },
  {
    path: "/",
    element:  <RequireAuth element={<Welcome />} />,
  },
  {
    path: "/inbox",
    element:  <RequireAuth element={<Inbox />} />
  },
  {
    path: "/dashboard",
    children: [
      {
        index: true,
        element:  <RequireAuth element={<Dashboard />} />
      },
      {
        path: "setup",
        element:  <RequireAuth element={<DashboardSetup/>} />
      },
    ]
  },


]

export default function MainContent() {
  const router = useRoutes(items);
  return router

}

1 Comment

This doesn't work for me. The index entry resolves fine, but the next child causes the page not to render and, in my case, throws the error: 'GET localhost:3000/characters/main.js net::ERR_ABORTED 404 (Not Found)' when trying to load 'localhost:3000/characters/new'
0

When setting path in childerns array you should allow using api history in dev server config:

  devServer: {
    historyApiFallback: true,
  }

here is a link to docs: https://webpack.js.org/configuration/dev-server/#devserverhistoryapifallback

and here is tutorial

https://youtu.be/acAH2_YT6bs?list=PL6DxKON1uLOHyPVa0XhcqcW2RhDytDpAI&t=4891

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.