Skip to content

常见的 Router 库有:

本节以 react-router@7 为例,介绍如何在 React 中使用路由。

1.Mode

react-router 支持 3 种模式,功能由简单到复杂分别为:

  • Declarative:声明式路由,使用 JSX 语法定义路由。
  • Data:对象式路由,使用对象定义路由。
  • Framework:框架式路由,使用框架的方式定义路由。区分 CSRSSG 以及 SSR

2.Create a Router and Render

bash
pnpm add react-router@7

然后在 React 中创建一个路由并渲染:

tsx
import {
  createBrowserRouter,
  RouterProvider,
} from "react-router";

import React from "react";
import ReactDOM from "react-dom/client";

const router = createBrowserRouter([
  {
    path: "/",
    element: <div>Hello World</div>,
  },
]);

const root = document.getElementById("root");

ReactDOM.createRoot(root).render(
  <RouterProvider router={router} />
);

3.createBrowserRouter

tsx
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 },
        ],
      },
			{
				path: "/teams/:teamId",
				loader: async ({ params }) => {
					let team = await fetchTeam(params.teamId);
					return { name: team.name };
				},
				Component: Team,
			},
			{
				path: "/lazy",
				lazy: async () => {
					// load component and loader in parallel before rendering
					const [Component, loader] = await Promise.all([
						import("./lazy"),
						import("./lazy-loader"),
					]);
					return { Component, loader };
				}
			}
    ],
  },
]);

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

上面的代码中涉及到了嵌套路由,类似于 Vue 中的 router-view,在 react 中我们需要使用 Outlet 组件来渲染子路由:

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

function Root() {
	return (
		<div>
			<h1>Root</h1>
			<Outlet />
		</div>
	);
}

4.Declarative Navigation

tsx
import { Link, NavLink } from 'react-router'

function Navbar() {
  return (
    <nav>
      <Link to="/">首页</Link>
      <NavLink to="/about">关于我们</NavLink>
    </nav>
  )
}
tsx
import { Navigate } from 'react-router-dom'

function LoginPage() {
  const user = useAuth()
  if (user) {
    return <Navigate to="/dashboard" replace />
  }
  return <LoginForm />
}
  • 在组件中返回 <Navigate />立即跳转到指定路由。
  • replace 表示替换浏览器历史记录(不会产生后退页面)。

5.Imperative Navigation

tsx
import { useNavigate } from 'react-router'

function LoginButton() {
  const navigate = useNavigate()

  const handleLogin = async () => {
    const result = await login()
    if (result.success) {
      navigate('/dashboard?token=123') // 编程式跳转
    }
  }

  return <button onClick={handleLogin}>登录</button>
}
js
navigate(to, {
  replace?: boolean,   // 是否替换历史记录(等于 <Navigate replace />)
  state?: any,         // 可以传递自定义状态,跳转后用 useLocation().state 获取
  relative?: "path" | "route"
})

// /users/abc
useParams()

// /search?keyword=abc
useSearchParams()