如何在 React Router 6 中制作多个 splats

how to make multiple splats in react router 6

我正在尝试升级到 React 路由器 6,但在尝试为每个路径使用多个 splat 时我遇到了问题。

基本上,我正在努力

/* ~~> project page
/*/~code/* ~~> file page

以下是项目页面的一些示例:

这里有一些文件页面(和其他子页面)的例子

这不是我们公司独有的。您可以在其他网站上看到它,例如 github:(尽管您可能会争辩说它们为所有者设置了固定长度) https://github.com/teambit/bit/tree/master/src/doctor.

从 React Router v4 开始,我用 path-to-regexp 来解决它,像这样:

<Route path="/:project(\w)"><ProjectPage/></Route>
<Route path="/:project(\w)/~code/:file(.*)"><FilePage/></Route>

但在 v6 中,情况似乎不再如此(参见 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.

老实说,我希望这种语法能够工作,但这是不允许的

<Routes>
  <Route path="*" element={<ProjectPage/>} />
  <Route path="*/~code" />
    <Route index element={<FilePage/>} />
    <Route path="*" element={<FilePage/>} />
  </Route>
</Routes>

这让我们回到 React 路由器 2,我们必须在其中手动执行此类路由。

太疯狂了,React Router 只有一份工作。有没有办法在 React Router 6 中实现这种类型的动态 url?

据我所知,这是不可能的。例如:

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>
    );
}

  • 永远无法访问通用代码页。
  • hello/~code ~> 将显示“特定代码页”
  • 其他任何内容都将获得“捕获所有页面”

似乎不​​再可能允许 "/" 的参数

我可以这样做,但这不是我拥有路由系统的原因:

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>
    );
}

如果我没有正确理解你的问题,你应该嵌套路由:

<Routes>
  <Route path=":project" element={<ProjectPage/>} />
</Routes>

我将 <ProjectPage/> 设为具有嵌套内部 <Routes/> 的递归元素,以便捕获每个 /:project/,并在遇到 /~code/ 时停止;与 v5 相比,它确实看起来很复杂。

另一种方法是根据自定义匹配项动态生成路由,如下所示:

const parentRegex = /([^~]*[^~/])(\/~)?/;
function NestedRoute() {
    const params = useParams();
    const splat = params["*"];

    const match = splat ? parentRegex.exec(splat) : null;
    const parentPath = match ? match[1] : "/";

    return (
        <Routes>
            <Route path={`${parentPath}/*`}>
                <Route index element={<ProjectPage id={parentPath} />} />
                <Route
                    path="~code/*"
                    element={<CodePage projectId={parentPath} />}
                />
            </Route>
        </Routes>
    );
}

虽然有一些缺点,但它有效:

  • 它将 ProjectPage 耦合到 CodePage(和以前一样,他们只需要知道相同的“路径”
  • 这不是通用的
  • 它可能会在 React Router 的下一个版本中中断