Nested Routing in React Router Dom V6

Viewed 93

I need two sets of routing in my app. One at the top level which routes between the different pages that don't need authentication and another set inside the authenticated area. Here's my top level route component.

function App() {
    return (
        <Router>
            <Routes>
                <Route path='/' element={<ProtectedRoute/>}>
                    <Route path='/' element={<Dashboard>
                        
                    </Dashboard>}/>
                </Route>
                <Route exact path="/sign-up" element={<SignUpPage/>}/>
                <Route exact path="/login" element={<LogInPage/>}/>
                <Route exact path="/activate-user" element={<ActivateUserPage/>}/>
                <Route exact path="/forgot-password" element={<ForgotPasswordPage/>}/>
                <Route exact path="/reset-password" element={<ResetPasswordPage/>}/>
            </Routes>
        </Router>
    );
}
export default App;

This is the protected route.

export const ProtectedRoute = () => {
    const auth = localStorage.getItem("xyz");
    return auth ? <Dashboard /> : <Navigate to="/login" />
}

This part works. Now I need a routing inside the Dashboard. Here's my dashboard component with the desired routing.

const Dashboard = () => {
    return (
        <nav>
             <ul>
                 <li><Link to=""><AiOutlineHome/></Link></li>
                 <li><Link to=""><AiOutlineHistory/></Link></li>
                 <li><Link to=""><BsFillPlusCircleFill/></Link></li>
                 <li><Link to=""><BsChatDots/></Link></li>
                 <li><Link to=""><RiUserSettingsLine/></Link></li>
              </ul>
        </nav>
            <section>
                <Route path='/feeds' element={<HomePage/>}/>
                <Route path='/capture' element={<CaptureStoryPage/>}/>
            </section>
        </div>
    )
}

This doesn't work and the error that I get is this:

router.ts:5 Uncaught Error: A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.

I'm new to React and could really use some help here. Thanks in advance.

1 Answers

Hopefully you meant for the ProtectedRoute to render an Outlet instead of the Dashboard component:

export const ProtectedRoute = () => {
  const auth = localStorage.getItem("xyz");
  return auth ? <Outlet /> : <Navigate to="/login" replace />;
}

If you need to render descendent routes in the Dashboard component then you need two things.

  1. The Route rendering Dashboard needs to append the "*" wildcard matcher to its route path so descendent routes can be matched.
  2. As the error points out, all Route components must be rendered by a Routes component or parent Route component, they can't be rendered directly.

Example:

function App() {
  return (
    <Router>
      <Routes>
        <Route element={<ProtectedRoute />}>
          <Route path='/*' element={<Dashboard />} /> // <-- match descendent routes
        </Route>
        <Route path="/sign-up" element={<SignUpPage />} />
        <Route path="/login" element={<LogInPage />} />
        <Route path="/activate-user" element={<ActivateUserPage />} />
        <Route path="/forgot-password" element={<ForgotPasswordPage />} />
        <Route path="/reset-password" element={<ResetPasswordPage />} />
      </Routes>
    </Router>
  );
}

...

const Dashboard = () => {
  return (
    <div>
      <nav>
        <ul>
          <li><Link to=""><AiOutlineHome/></Link></li>
          <li><Link to=""><AiOutlineHistory/></Link></li>
          <li><Link to=""><BsFillPlusCircleFill/></Link></li>
          <li><Link to=""><BsChatDots/></Link></li>
          <li><Link to=""><RiUserSettingsLine/></Link></li>
        </ul>
      </nav>
      <section>
        <Routes> // <-- wrap routes in `Routes`
          <Route path='/feeds' element={<HomePage/>}/>
          <Route path='/capture' element={<CaptureStoryPage/>}/>
        </Routes>
      </section>
    </div>
  );
};
Related