react-router
react-router copied to clipboard
[Feature]: Support using useRoutes nested in <Routes>
What is the new or updated feature that you are suggesting?
I want to be able to use the output of useRoutes
nested as a child of the <Routes>
element.
Context
I have a library that implements a shared login workflow that is used by multiple applications. The login screen routes are known in advance, and the main application route configuration is passed as children.
Essentially, in v5 I could do:
<BrowserRouter>
<>
{/* Login and Registration Routes */ }
</>
<AuthGuard>
{children} {/* Main Application Content */}
</AuthGuard>
</BrowserRouter>
In v6, I'm stuck because I need to either:
- wrap everything in a single
<Routes>
component- in this case the consuming applications have to pass in a collection of
<Route>
elements- there's no flexibility for them to configure routes with
useRoutes
or to wrap their routes in a shared layout-type component since all children of<Routes>
must be<Route>
- there is no way for them to define their routes in separate files/ components for the same reason
- there's no flexibility for them to configure routes with
- in this case the consuming applications have to pass in a collection of
- allow the main application content to sit adjacent to the Login screens, similar to the v5 approach
- this allows the main application to pass in its routes any way they like, but you end up with multiple instances of
<Routes>
and you run into the whole 'no routes matched' issue (#8095). - Two big drawbacks to this approach:
- the main application route config can no longer have a catch-all route (e.g., any nonexistent route redirects to the homepage) because that catch-all route will catch the routes for the Login screens that are defined in the other
<Routes>
container leading to an infinite loop of re-routing / re-rendering. - the library can no longer handle the AuthGuard piece...this responsibility has to get pushed down to the main application (back to the
<Routes>
can only have<Route>
children issue).
- the main application route config can no longer have a catch-all route (e.g., any nonexistent route redirects to the homepage) because that catch-all route will catch the routes for the Login screens that are defined in the other
- this allows the main application to pass in its routes any way they like, but you end up with multiple instances of
Ideally, it would be nice if <Routes>
could support items other than <Route>
as children, even if it's just being able to use useRoutes
nested under a <Routes>
wrapper (that would open up the ability to use option 1 above, but with the flexibility to support dynamic routes defined either declaratively or using the hook):
const MyRoutes = useRoutes([...]);
<Routes>
<Route {...props}/>
{MyRoutes}
</Routes>
Why should this feature be included?
This would open up a lot more flexibility in terms of how routes can be defined. The behavior was achievable in v5. It seems like this would be a relatively common use case.
The closest I've gotten to ideal usage is doing option 1 and passing in an all-encompassing route whose element can be used for shared layout and children can be defined in another file. The only drawback here is that the routes still must be defined using <Route>
elements (not a show-stopper for migration since useRoutes is new in v6 anyway, but it would still be convenient to be able to mix the two approaches).
// The main application routes — can be defined elsewhere in separate files
const AppRoutes = (
<>
<Route {...props}/>
<Route {...props}/>
{/* ...etc */}
</>
);
// layout or wrapper element(s) shared by all routes
const SharedLayoutWrapper = () => (
<LayoutWrapper>
<SomeSharedComponent/>
<Outlet/> {/* application routes will get rendered here */}
</LayoutWrapper>
);
export const App = () => (
<LoginLibraryComponent>
<Route path={''} element={<SharedLayoutWrapper/>} >
{AppRoutes}
</Route>
</LoginLibraryComponent>
)
I'm going to convert this to a discussion so it can go through our new Open Development process. Please upvote the new Proposal if you'd like to see this considered!