I'm trying to upgrade to react router 6, and I'm breaking when trying to use more than one splat per path.
basically, I'm trying to do
/* ~~> project page
/*/~code/* ~~> file page
here are some examples of the project page:
- https://hu9y25l.scopes.teambit.cloud/routing/nav-link
- https://hu9y25l.scopes.teambit.cloud/graph/tree/root-node
- https://hu9y25l.scopes.teambit.cloud/routing/compare-url
- https://hu9y25l.scopes.teambit.cloud/hooks/use-graphql-light
here are some examples of a file page (and other subpages)
- https://hu9y25l.scopes.teambit.cloud/routing/nav-link/~code https://hu9y25l.scopes.teambit.cloud/layout/grid-component/~code/grid-template/grid-template.module.scss
- https://hu9y25l.scopes.teambit.cloud/routing/compare-url/~code/compare-url.tsx
- https://hu9y25l.scopes.teambit.cloud/input/button/~dependencies
- https://hu9y25l.scopes.teambit.cloud/input/button/~compositions
This is not unique to our company. You can see it in other sites, like github: (although you could argue they have a fixed length for the owner) https://github.com/teambit/bit/tree/master/src/doctor.
since React Router v4, I used to solve it with path-to-regexp, like this:
<Route path="/:project(\\w)"><ProjectPage/></Route>
<Route path="/:project(\\w)/~code/:file(.*)"><FilePage/></Route>
but in v6, this doesn't seem to be the case anymore (see here)
React Router v6 uses a simplified path format. in v6 supports only 2 kinds of placeholders: dynamic :id-style params and * wildcards. A * wildcard may be used only at the end of a path, not in the middle.
I honestly expected this syntax to work, but it is not allowed
<Routes>
<Route path="*" element={<ProjectPage/>} />
<Route path="*/~code" />
<Route index element={<FilePage/>} />
<Route path="*" element={<FilePage/>} />
</Route>
</Routes>
This takes us back to react router 2, where we had to do this type of routing manually.
It's crazy, React Router had only one job. Is there a way to achieve this type of dynamic urls in React Router 6?
CodePudding user response:
as far as I can see, it's not possible. for example:
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="*" element={<div>catch all page</div>} />
<Route path="*/~code" element={<div>generic code page</div>} /> {/* <--- this is just ignored */}
<Route path="hello/~code" element={<div>specific code page</div>} />
</Routes>
</BrowserRouter>
);
}
- generic code page is never reachable.
- hello/~code ~> will show "specific code page"
- anything else will get "catch all page"
it seems that params allowing "/"
are no longer possible
I could do this, but it's not why I have a routing system:
function App() {
return (
<BrowserRouter>
<Routes>
<Route path=":id" element={<div>catch all page</div>} />
<Route path=":id/:id2" element={<div>catch all page</div>} />
<Route path=":id/:id2/:id3" element={<div>catch all page</div>} />
<Route path=":id/:id2/:id3/:id4" element={<div>catch all page</div>} />
<Route path=":id/:id2/:id3/:id4/:id5" element={<div>catch all page</div>} />
<Route path=":id/~code" element={<div>generic code page</div>} />
<Route path=":id/:id2/~code" element={<div>generic code page</div>} />
<Route path=":id/:id2/:id3/~code" element={<div>generic code page</div>} />
<Route path=":id/:id2/:id3/:id4/~code" element={<div>generic code page</div>} />
<Route path=":id/:id2/:id3/:id4/:id5/~code" element={<div>generic code page</div>} />
<Route path="hello/~code" element={<div>specific code page</div>} />
</Routes>
</BrowserRouter>
);
}
CodePudding user response:
If I understood your question correctly, you should nest the routes:
<Routes>
<Route path=":project" element={<ProjectPage/>} />
</Routes>
I'd make <ProjectPage/>
a recursive element with nested inner <Routes/>
in order to catch every /:project/
, and stop when I happen upon /~code/
; it indeed seems convoluted in comparison to v5.