Search code examples
javascriptreactjsreact-router-domrbac

Error in implementing RBAC Protected routes in React Router V6


I know how to implement protected routes in the React-Router V6, but I wanna go a bit more modular approach. My application is large and I want to separate all the role based routes. For example, there will be an "AdminRoutes" component which would contain all the routes for the admin and then I will add it as a "ProtectedRoute" children.

In short, instead of this:

<Routes>
  <Route element={<ProtectedRoutes />}>
    <Route path='/admin' element={<AdminPage />} />
    <Route path='/profile' element={<Profile />} />
  </Route>
</Routes>

I want to have this:

<Routes>
  <Route element={<ProtectedRoutes />}>
    <AdminRoutes />
  </Route>
</Routes>

Where the AdminRoutes component would return the admin routes like:

export function AdminRoutes() {
  return (
    <>
      <Route path='/admin' element={<AdminPage />} />
      <Route path='/profile' element={<Profile />} />
    </>
  )
}

Note: the ProtectedRoutes component will return children (outlet) or navigate to a different route based on some logic Currently it's giving me error that "Uncaught Error: All component children of <Routes> must be a <Route> or <React.Fragment>".

Is what I am saying possible? If you know any other better approach than this, I would also wanna know that.


Solution

  • Currently it's giving me error that "Uncaught Error: All component children of <Routes> must be a <Route> or <React.Fragment>"

    You can't render directly the Route component, it must have either a Routes component as its parent, or another Route component in the case of nested routes. AdminRoutes is neither a Route or React.Fragment component so it cannot be rendered as a child of Routes or Route.

    In AdminRoutes wrap the routes in the Routes component so it can correctly render the descendent routes.

    export function AdminRoutes() {
      return (
        <Routes>
          <Route path="/admin" element={<AdminPage />} />
          <Route path="/profile" element={<Profile />} />
        </Routes>
      );
    }
    

    Is what I am saying possible?

    Yes, but since you are converting nested routes into descendent routes, the main router needs to render AdminRoutes on a route as well, not alone by itself as a child of Route (for the same reason above).

    Render AdminRoutes as a routed component on path="/*" with the trailing splat so all descendent routes (e.g. routes rendered in component's Routes component) can also be matched and rendered.

    <Routes>
      <Route element={<ProtectedRoutes />}>
        <Route path="/*" element={<AdminRoutes />} />
      </Route>
    </Routes>
    

    Demo

    Edit error-in-implementing-rbac-protected-routes-in-react-router-v6