javascript - 使用 react router v4/v5 的巢狀路由
我目前在使用 React Router v4 進行嵌套路由時遇到困難。
最接近的例子是在 React-Router v4 文件中的路由配置。
我想把我的應用程式分成兩個不同的部分。
前端和管理區域。
我正在想像類似這樣的東西:
<Match pattern="/" component={Frontpage}>
<Match pattern="/home" component={HomePage} />
<Match pattern="/about" component={AboutPage} />
</Match>
<Match pattern="/admin" component={Backend}>
<Match pattern="/home" component={Dashboard} />
<Match pattern="/users" component={UserPage} />
</Match>
<Miss component={NotFoundPage} />
前端的佈局和樣式與管理區域不同。因此,在首頁中,路由 home、about 等應該是子路由。
/home 應該呈現在 Frontpage 元件中,而 /admin/home 應該呈現在 Backend 元件中。
我嘗試了一些其他變化,但我總是最後沒有訪問到 /home 或 /admin/home。
答案#1
在 react-router-v4 中,你不會嵌套 <Routes />。相反的,你會將它們放在另一個 <Component /> 內。
例如
<Route path='/topics' component={Topics}>
<Route path='/topics/:topicId' component={Topic} />
</Route>
應該變成
<Route path='/topics' component={Topics} />
和
const Topics = ({ match }) => (
<div>
<h2>Topics</h2>
<Link to={`${match.url}/exampleTopicId`}>
Example topic
</Link>
<Route path={`${match.path}/:topicId`} component={Topic}/>
</div>
)
這是一個直接來自 react-router 文件的基本範例。
答案#2
react-router v6
2022 更新 - v6 有嵌套的 Route 元件,能直接運作™。
這個問題是關於 v4/v5 的,但現在最好的答案是 如果可以就直接用 v6!
請參見此部落格文章中的範例程式碼。不過,如果你暫時無法升級...
react-router v4 & v5
確實,為了嵌套路由,你需要將它們放在 Route 的子組件中。
不過,如果你更喜歡使用內聯語法 而不是將你的 Routes 拆分到不同的組件中,你可以向你想要嵌套的 Route 提供一個函數式組件作為 render 屬性。
<BrowserRouter>
<Route path="/" component={Frontpage} exact />
<Route path="/home" component={HomePage} />
<Route path="/about" component={AboutPage} />
<Route
path="/admin"
render={({ match: { url } }) => (
<>
<Route path={`${url}/`} component={Backend} exact />
<Route path={`${url}/home`} component={Dashboard} />
<Route path={`${url}/users`} component={UserPage} />
</>
)}
/>
</BrowserRouter>
如果你對為什麼應該使用 render 屬性而不是 component 屬性感興趣,那是因為它可以防止內聯函數組件在每次渲染時重新掛載。更多詳情請參見文檔。
請注意,範例將巢狀的路由包裹在 Fragment 中。在 React 16 之前,你可以改用容器 <div>。
答案#3
只是想提一下,自從這個問題被提出/回答以來,react-router v4 已經發生了根本性的改變。
已經沒有 <Match> 元件了!<Switch> 用來確保只渲染第一個符合項。<Redirect> 嗯……會重定向到另一個路由。使用或忽略 exact 來包含或排除部分匹配。
查看文件。它們非常棒。https://reacttraining.com/react-router/
這是一個我希望可用來回答你問題的例子。
<Router>
<div>
<Redirect exact from='/' to='/front'/>
<Route path="/" render={() => {
return (
<div>
<h2>Home menu</h2>
<Link to="/front">front</Link>
<Link to="/back">back</Link>
</div>
);
}} />
<Route path="/front" render={() => {
return (
<div>
<h2>front menu</h2>
<Link to="/front/help">help</Link>
<Link to="/front/about">about</Link>
</div>
);
}} />
<Route exact path="/front/help" render={() => {
return <h2>front help</h2>;
}} />
<Route exact path="/front/about" render={() => {
return <h2>front about</h2>;
}} />
<Route path="/back" render={() => {
return (
<div>
<h2>back menu</h2>
<Link to="/back/help">help</Link>
<Link to="/back/about">about</Link>
</div>
);
}} />
<Route exact path="/back/help" render={() => {
return <h2>back help</h2>;
}} />
<Route exact path="/back/about" render={() => {
return <h2>back about</h2>;
}} />
</div>
</Router>
希望這有幫助,告訴我。如果這個例子沒有充分回答你的問題,告訴我,我會看看是否能修改它。
答案#4
我成功地通過用 Switch 包裹來定義巢狀路由,並且在根路由之前定義巢狀路由。
<BrowserRouter>
<Switch>
<Route path="/staffs/:id/edit" component={StaffEdit} />
<Route path="/staffs/:id" component={StaffShow} />
<Route path="/staffs" component={StaffIndex} />
</Switch>
</BrowserRouter>
參考資料:https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/Switch.md
答案#5
使用 Hooks
最新的 hooks 更新是使用 useRouteMatch。
主要路由組件
export default function NestingExample() {
return (
<Router>
<Switch>
<Route path="/topics">
<Topics />
</Route>
</Switch>
</Router>
);
}
子元件
function Topics() {
// The `path` lets us build <Route> paths
// while the `url` lets us build relative links.
let { path, url } = useRouteMatch();
return (
<div>
<h2>Topics</h2>
<h5>
<Link to={`${url}/otherpath`}>/topics/otherpath/</Link>
</h5>
<ul>
<li>
<Link to={`${url}/topic1`}>/topics/topic1/</Link>
</li>
<li>
<Link to={`${url}/topic2`}>/topics/topic2</Link>
</li>
</ul>
// You can then use nested routing inside the child itself
<Switch>
<Route exact path={path}>
<h3>Please select a topic.</h3>
</Route>
<Route path={`${path}/:topicId`}>
<Topic />
</Route>
<Route path={`${path}/otherpath`>
<OtherPath/>
</Route>
</Switch>
</div>
);
}
