路由
本页内容

路由

配置路由

路由被配置为 createBrowserRouter 的第一个参数。至少需要一个路径 (path) 和一个组件 (component)

import { createBrowserRouter } from "react-router";

function Root() {
  return <h1>Hello world</h1>;
}

const router = createBrowserRouter([
  { path: "/", Component: Root },
]);

这是一个更大的示例路由配置

createBrowserRouter([
  {
    path: "/",
    Component: Root,
    children: [
      { index: true, Component: Home },
      { path: "about", Component: About },
      {
        path: "auth",
        Component: AuthLayout,
        children: [
          { path: "login", Component: Login },
          { path: "register", Component: Register },
        ],
      },
      {
        path: "concerts",
        children: [
          { index: true, Component: ConcertsHome },
          { path: ":city", Component: ConcertsCity },
          { path: "trending", Component: ConcertsTrending },
        ],
      },
    ],
  },
]);

路由对象

路由对象定义了路由除路径和组件之外的行为,例如数据加载和操作。我们会在路由对象指南中详细介绍,这里是一个 loader 的快速示例。

import {
  createBrowserRouter,
  useLoaderData,
} from "react-router";

createBrowserRouter([
  {
    path: "/teams/:teamId",
    loader: async ({ params }) => {
      let team = await fetchTeam(params.teamId);
      return { name: team.name };
    },
    Component: Team,
  },
]);

function Team() {
  let data = useLoaderData();
  return <h1>{data.name}</h1>;
}

嵌套路由

路由可以通过 children 嵌套在父路由中。

createBrowserRouter([
  {
    path: "/dashboard",
    Component: Dashboard,
    children: [
      { index: true, Component: Home },
      { path: "settings", Component: Settings },
    ],
  },
]);

父路由的路径会自动包含在子路由中,因此此配置会创建 "/dashboard""/dashboard/settings" 这两个 URL。

子路由通过父路由中的 <Outlet/> 渲染。

import { Outlet } from "react-router";

export default function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>
      {/* will either be <Home> or <Settings> */}
      <Outlet />
    </div>
  );
}

布局路由

省略路由中的 path 会为其子路由创建新的嵌套路由,而不会向 URL 添加任何片段 (segment)。

createBrowserRouter([
  {
    // no path on this parent route, just the component
    Component: MarketingLayout,
    children: [
      { index: true, Component: Home },
      { path: "contact", Component: Contact },
    ],
  },

  {
    path: "projects",
    children: [
      { index: true, Component: ProjectsHome },
      {
        // again, no path, just a component for the layout
        Component: ProjectLayout,
        children: [
          { path: ":pid", Component: Project },
          { path: ":pid/edit", Component: EditProject },
        ],
      },
    ],
  },
]);

注意

  • HomeContact 将渲染到 MarketingLayout 的 outlet 中
  • ProjectEditProject 将渲染到 ProjectLayout 的 outlet 中,而 ProjectsHome 则不会。

索引路由

索引路由通过在没有路径的路由对象上设置 index: true 来定义。

{ index: true, Component: Home }

索引路由会渲染到其父路由的 Outlet 中,并使用父路由的 URL(就像默认子路由一样)。

import { createBrowserRouter } from "react-router";

createBrowserRouter([
  // renders at "/"
  { index: true, Component: Home },
  {
    Component: Dashboard,
    path: "/dashboard",
    children: [
      // renders at "/dashboard"
      { index: true, Component: DashboardHome },
      { path: "settings", Component: DashboardSettings },
    ],
  },
]);

请注意,索引路由不能有子路由。

前缀路由

仅包含 path 而没有 component 的路由会创建一组带有 path 前缀的路由。

createBrowserRouter([
  {
    // no component, just a path
    path: "/projects",
    children: [
      { index: true, Component: ProjectsHome },
      { path: ":pid", Component: Project },
      { path: ":pid/edit", Component: EditProject },
    ],
  },
]);

这创建了路由 /projects/projects/:pid/projects/:pid/edit,而无需引入布局组件。

动态路由段

如果一个路径段以 : 开头,那么它就成为一个“动态路由段”。当路由匹配 URL 时,动态路由段将从 URL 中解析出来,并作为 params 提供给其他路由 API。

{
  path: "teams/:teamId",
  loader: async ({ params }) => {
    // params are available in loaders/actions
    let team = await fetchTeam(params.teamId);
    return { name: team.name };
  },
  Component: Team,
}
import { useParams } from "react-router";

function Team() {
  // params are available in components through useParams
  let params = useParams();
  // ...
}

你可以在一个路由路径中包含多个动态路由段

{
  path: "c/:categoryId/p/:productId";
}

可选路由段

你可以在路由段的末尾添加一个 ? 来将其设为可选。

{
  path: ":lang?/categories";
}

你也可以有可选的静态路由段

{
  path: "users/:userId/edit?";
}

星号路由段 (Splats)

也称为“捕获所有”(catchall)或“星号”(star)路由段。如果一个路由路径模式以 /* 结尾,那么它将匹配 / 后面的任何字符,包括其他 / 字符。

{
  path: "files/*";
  loader: async ({ params }) => {
    params["*"]; // will contain the remaining URL after files/
  };
}

你可以解构 *,只需要给它赋一个新名称。一个常见的名称是 splat

const { "*": splat } = params;

下一篇:路由对象

文档和示例 CC 4.0