7、React Router v6 实战

5 阅读3分钟

太棒了!👏 你已经掌握了 React 的状态管理和类型安全,现在是时候让你的应用“动起来”—— 支持多页面跳转!


—— 构建单页应用(SPA)的导航系统

🎯 目标:实现页面路由、动态路径、嵌套路由、编程式导航和权限控制。


一、为什么需要路由?🧭

在真实项目中,用户需要访问不同页面:

  • 首页 /
  • 用户详情 /user/123
  • 博客文章 /posts/react-tutorial
  • 登录页 /login

React 是单页应用(SPA) ,不能靠刷新页面切换。
👉 所以我们需要 前端路由库 —— React Router


二、安装与基本结构

1. 安装

npm install react-router-dom

2. 基本组件

组件作用
<BrowserRouter>路由根容器(使用 HTML5 History API)
<Routes>包含所有路由规则
<Route>定义单条路由
<Link> / <NavLink>导航链接(不刷新页面)

三、基础用法:静态路由 ✅

// main.tsx 或 App.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Contact from './pages/Contact';

function App() {
  return (
    <BrowserRouter>
      <nav>
        <Link to="/">首页</Link>
        <Link to="/about">关于我们</Link>
        <Link to="/contact">联系</Link>
      </nav>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/contact" element={<Contact />} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;

✅ 注意:

  • path="/" 是根路径
  • element={<Component />} 指定要渲染的组件

四、动态路由:参数传递 🧩

用于显示不同用户的详情、不同文章等。

示例:用户详情页 /user/:id

// routes:
<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/user/:id" element={<UserProfile />} />
</Routes>

在组件中获取参数:

// UserProfile.tsx
import { useParams } from 'react-router-dom';

function UserProfile() {
  const { id } = useParams(); // 获取动态参数

  return <h2>查看用户 ID: {id}</h2>;
}

✅ 支持多个参数:

// 路径:/post/:year/:month/:day
const { year, month, day } = useParams();

五、嵌套路由:布局复用 🧱

适用于有公共布局的页面,如:

  • 头部 + 侧边栏 + 内容区
  • 只有内容区变化

示例:博客后台管理系统

// App.tsx
<Routes>
  <Route path="/" element={<Layout />}>
    <Route index element={<Dashboard />} /> {/* 默认子路由 */}
    <Route path="posts" element={<Posts />} />
    <Route path="users" element={<Users />} />
    <Route path="settings" element={<Settings />} />
  </Route>
  <Route path="/login" element={<Login />} />
</Routes>

Layout 组件中使用 <Outlet> 渲染子路由:

// Layout.tsx
import { Outlet, Link } from 'react-router-dom';

function Layout() {
  return (
    <div style={{ display: 'flex' }}>
      <nav style={{ width: 200, borderRight: '1px solid #ccc' }}>
        <ul>
          <li><Link to="/">仪表盘</Link></li>
          <li><Link to="posts">文章管理</Link></li>
          <li><Link to="users">用户管理</Link></li>
        </ul>
      </nav>
      <main style={{ padding: 20 }}>
        <Outlet /> {/* 子路由在这里渲染 */}
      </main>
    </div>
  );
}

六、编程式导航:代码跳转 ⚙️

有时候你不希望用户点击链接,而是通过逻辑控制跳转。

使用 useNavigate Hook

import { useNavigate } from 'react-router-dom';

function LoginButton() {
  const navigate = useNavigate();

  const handleLogin = () => {
    // 模拟登录成功
    console.log('登录成功');
    navigate('/dashboard'); // 跳转到首页
  };

  return <button onClick={handleLogin}>登录</button>;
}

其他跳转方式:

navigate(-1);        // 后退一页
navigate(1);         // 前进一页
navigate('/search', { replace: true }); // 替换当前历史记录

七、搜索参数(Query Params)🔍

URL 中 ? 后的部分,如 /search?q=react&type=tutorial

获取 query 参数

import { useSearchParams } from 'react-router-dom';

function SearchPage() {
  const [searchParams, setSearchParams] = useSearchParams();
  const q = searchParams.get('q');
  const type = searchParams.get('type');

  const handleFilter = (newType) => {
    setSearchParams({ q, type: newType });
  };

  return (
    <div>
      <p>搜索关键词:{q}</p>
      <p>类型:{type}</p>
      <button onClick={() => handleFilter('all')}>全部</button>
      <button onClick={() => handleFilter('blog')}>博客</button>
      <button onClick={() => handleFilter('video')}>视频</button>
    </div>
  );
}

✅ URL 自动变为:/search?q=react&type=blog


八、权限路由(私有路由)🔐

某些页面只有登录后才能访问,比如 /dashboard

创建一个受保护的路由组件

// components/PrivateRoute.tsx
import { Navigate } from 'react-router-dom';
import { useAuth } from '../hooks/useAuth'; // 假设你有一个 auth 状态

function PrivateRoute({ children }: { children: JSX.Element }) {
  const { isLoggedIn } = useAuth();

  if (!isLoggedIn) {
    return <Navigate to="/login" replace />;
  }

  return children;
}

使用方式:

<Routes>
  <Route path="/login" element={<Login />} />

  <Route
    path="/dashboard"
    element={
      <PrivateRoute>
        <Dashboard />
      </PrivateRoute>
    }
  />
</Routes>

✅ 当未登录时,自动重定向到 /login


九、实战练习 🏋️‍♀️

✅ 练习 1:构建博客路由系统

实现以下页面和路由:

  • / → 首页(文章列表)
  • /post/:slug → 文章详情(如 /post/react-router-tutorial
  • /category/:name → 分类页面
  • /about → 关于我们

要求:

  • 使用 <Link> 实现导航
  • PostDetail 中用 useParams() 获取 slug 并显示标题

✅ 练习 2:带搜索功能的文章列表

  • 路径:/search
  • 支持 ?q=关键词
  • 显示“搜索结果:xxx”
  • 添加输入框,回车后更新 query 参数

✅ 练习 3:登录后才能访问的个人中心

  1. 创建 /profile 页面
  2. 如果未登录(可用 const isLoggedIn = false 模拟),重定向到 /login
  3. 登录按钮点击后设置 isLoggedIn = true 并跳转回 /profile

✅ 总结:React Router v6 核心要点

功能关键 API
基础路由<BrowserRouter>, <Routes>, <Route>
导航链接<Link>, <NavLink>(带激活样式)
动态参数:id, useParams()
嵌套路由<Outlet> + 父子结构
编程式导航useNavigate()
查询参数useSearchParams()
重定向<Navigate to="/path" />
权限控制自定义 PrivateRoute 组件

🎯 下一步预告
你已经能构建完整的多页面应用了!接下来我们要优化用户体验:

➡️ React 性能优化技巧
—— 避免不必要的渲染、懒加载组件、使用 Memo、Code Splitting

是否继续?我将带你进入 第九课:React 性能优化实战