如何在 React Router 6 中制作多个 splats
how to make multiple splats in react router 6
我正在尝试升级到 React 路由器 6,但在尝试为每个路径使用多个 splat 时我遇到了问题。
基本上,我正在努力
/* ~~> project page
/*/~code/* ~~> file 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
这里有一些文件页面(和其他子页面)的例子
- 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
这不是我们公司独有的。您可以在其他网站上看到它,例如 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 的下一个版本中中断
我正在尝试升级到 React 路由器 6,但在尝试为每个路径使用多个 splat 时我遇到了问题。
基本上,我正在努力
/* ~~> project page
/*/~code/* ~~> file 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
这里有一些文件页面(和其他子页面)的例子
- 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
这不是我们公司独有的。您可以在其他网站上看到它,例如 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 的下一个版本中中断