Home > OS >  how to make multiple splats in react router 6
how to make multiple splats in react router 6

Time:05-19

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:

here are some examples of a file page (and other subpages)

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.

  • Related