路由被配置为 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 },
],
},
],
},
]);
注意
Home
和 Contact
将渲染到 MarketingLayout
的 outlet 中Project
和 EditProject
将渲染到 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?";
}
也称为“捕获所有”(catchall)或“星号”(star)路由段。如果一个路由路径模式以 /*
结尾,那么它将匹配 /
后面的任何字符,包括其他 /
字符。
{
path: "files/*";
loader: async ({ params }) => {
params["*"]; // will contain the remaining URL after files/
};
}
你可以解构 *
,只需要给它赋一个新名称。一个常见的名称是 splat
const { "*": splat } = params;
下一篇:路由对象