React Router v6 - 无需 Outlet 实现嵌套路由

10

我在使用react-router v6,是否可以在不使用Outlet组件的情况下使用嵌套路由?

例如: 我有一个用户页面,当点击用户组件时,应该导航到特定的用户页面。

当前尝试:

 <Routes>
   <Route path="/" element={<Home />} />
   <Route path="/users" element={<Users />} />
     <Route path=":id" element={<UserPage/>} />
 </Routes>

当点击特定用户时:

const gotoUserPage = () => {
  navigate('1')
}

gotoUserPage将URL从'/users'更改为'/users/1',但userPage组件未呈现。
6个回答

15

是否可以不使用Outlet组件来使用嵌套路由?

不行,必须使用Outlet组件才能呈现嵌套的Route组件。

要么在Users组件中渲染Outlet组件,要么直接将其作为布局组件渲染。

<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/users" element={<Outlet />}>
    <Route index element={<Users />} />        // "/users"
    <Route path=":id" element={<UserPage/>} /> // "/users/:id"
  </Route>
</Routes>
虽然更好或更准确的问题可能是,您是否需要将 Outlet 明确渲染为布局元素?答案可能出乎意料地是“不需要”。Route 组件默认在 element 属性上呈现一个 Outlet

默认的 <Route element> 是一个 <Outlet>。这意味着路由即使没有显式的 element prop,仍将呈现其子元素,因此您可以在子路由元素周围嵌套 UI 路径而无需嵌套 UI。

您只需将一些嵌套路由包装在 Route 中,并仅指定嵌套的 path,嵌套路由将默认呈现为 Outlet
<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/users">
    <Route index element={<Users />} />        // "/users"
    <Route path=":id" element={<UserPage/>} /> // "/users/:id"
  </Route>
</Routes>

1
我曾经苦恼于如何让一个子路由“替换”其父路由。包装解决方案非常有效,谢谢。 - mehdix

5

使用 <Outlet/> 组件有什么问题?它告诉 React Router 渲染 <UserPage/> 的位置,没有它,页面就没有地方可渲染了,正如预期的那样。

如果你想知道如何在不将其作为<Users/>页面的子元素的情况下渲染页面,则可以尝试以下方法:

<Routes>
   <Route path="/" element={<Home />} />
   <Route path="users" element={<Outlet />} />
     <Route path="/" element={<Users />} />
     <Route path=":id" element={<UserPage />} />
 </Routes>

有时候确实需要一个全新的组件,但在大多数情况下,组件会共享某些部分,例如导航栏和容器。如果Users和UserPage组件都有导航栏,则应考虑将其从两个组件中重构出来,并将其放入具有导航栏和Outlet的父组件中。这样做有助于随着规模扩大来管理组件。


<Route path="/" element={<Users />} />抛出错误,因为嵌套路由不能是绝对路径(以 / 开头)。有什么替代方案吗? - Adarsh Chakraborty
@AdarshChakraborty 使用索引路由而不是 <Route index element={<Users />} />。https://reactrouterdotcom.fly.dev/docs/en/v6/getting-started/overview#index-routes - Vočko
如果省略路径属性,则上述代码可以正常工作:<Route element={<Users />} /> - Dave

3

这是一种优化的方法,可以实现@hellocng所解释的内容:

<Routes>
   <Route path="/" element={<Home />} />
   <Route path="users" element={<Outlet />}>
     <Route index element={<Users />} />
     <Route path=":id" element={<UserPage />} />
   </Route>
 </Routes>

2

可以在不使用 <Outlet /> 组件的情况下使用路由,只需按下面所示的方式操作即可。使用与父组件相同的路径,并添加 :id

 <Routes>
   <Route path="/" element={<Home />} />
   <Route path="/users" element={<Users />} />
   <Route path="users/:id" element={<UserPage/>} />
 </Routes>

然而,如果您担心嵌套时<Outlet />组件与父组件在同一页上呈现,则可以像这样在子组件处于活动状态时隐藏父组件:

1. 使用Flat Routes

<UserPage />组件添加到路由中,如下所示:

<Routes>
   <Route path="/" element={<Home />} />
   <Route path="users" element={<Users />} >
     <Route path=":id" element={<UserPage />} />
   </Route>
 </Routes>

2. 父组件条件渲染

如果存在 params.id 属性,则添加条件以不渲染父组件的内容,这使用 Outlet 但帮助避免显示某些元素。

let params = useParams();
<div>
!params.id && (<div>
*render your contents here* </div>)
<Outlet />
</div>

每当子组件加载时,父组件就不可见了。

1
只是术语上的更正,你的第一个示例并不是路由嵌套,而只是一组平面路由。在第二个示例中,“Users”组件必须渲染“Outlet”组件,以便嵌套路由可以呈现“UserPage”,这正是OP所问的问题或试图避免的问题。 - Drew Reese

1
我正在使用嵌套的<Routes></Routes>组件在react-router-dom v6中,并且它正在工作。但是在控制台中有时会出现警告信息"No routes matched location ...someLocation...",我猜想这种方法是否正确。但是对我来说使用<Outlet/>不方便。 在下面的示例中,PageRouting包含PagePage包含NestedPageRoutingNestedPageRouting包含NestedPage。路径段末尾的斜杠和星号(/*)允许嵌套路由。注释中路径中的第一个斜杠假设<PageRouting/>是根路由。
function PageRouting(){
  return <Routes>
    {/* path: /page */}
    <Route path="page/*" element={<Page/>}/>
    <Route path='*' element={<div>No routes matched</div>}/>
  </Routes>
}

function Page(){
  return <div>
    <div>Some content</div>
    <NestedPageRouting/>
  </div>
}

function NestedPageRouting(){
  return <Routes>
    {/* path: /page/nestedPage */}
    <Route path="nestedPage/*" element={<NestedPage/>}/>
    <Route path='*' element={<div>No routes matched</div>}/>
  </Routes>
}

function NestedPage(){
  return <div>Some Nested Content</div>
}

0

是的,你可以用一些技巧来实现这个。

  • 首先创建一个输出组件(<OutletPage />
  • 然后创建一个页面,当有人访问该路由时实际需要呈现该页面

就像这样

<Route path="profile" element={<ProfilePageOutlet />}>
     <Route index element={<ProfilePage />} />
     <Route path="my-profile" element={<MyProfilePage />} />
</Route>

<ProfilePageOutlet />看起来像这样

import { Outlet } from "react-router-dom";

function ProfilePageOutlet() {
  return <Outlet />;
}

export default ProfilePageOutlet;

<MyProfilePage /> 是一个简单的页面


他们明确表示“不使用Outlet组件”,这显然没有回答问题。 - leverglowh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接