React Router v6 全面指南:从入门到实战,看这篇就够了

88 阅读7分钟

本文基于 React Router v6 编写,已剔除过时的 v5 语法,请放心食用。  

为什么我们需要 React Router?

在开始写代码之前,咱们先通俗地聊聊 React Router 到底是干嘛的,以及为什么现在的 React 项目离不开它。

打个比方:从“翻书”到“PPT”

想象一下你正在看内容展示:

  • 没有路由的传统网页 (MPA)
    就像在看书。每当你点击链接(翻页),浏览器都要把当前这页纸撕掉,重新去服务器拿一张新纸,重新排版、重新渲染。你会看到屏幕白屏闪烁一下,体验断层,效率也低。

  • 使用了 React Router 的单页应用 (SPA)
    就像在播放 PPT。你的浏览器窗口就是那个投影幕布(容器),它始终不动。当你点击导航时,React Router 这个“放映员”只是不仅刷新地把 PPT 的某一页内容(组件)替换到了屏幕中间

    幕布没变,只有内容在变。  这种体验就像原生 App 一样丝滑,没有白屏,无需等待整个页面重载。

它的三大核心超能力

  1. 无感切换 (No Refresh)
    这是最直观的体验。用户在页面间跳转时,浏览器不会重新加载整个 HTML。这对于用户体验是质的飞跃。

  2. URL 也就是地图 (Source of Truth)
    你可能会问:“既然是换组件,我自己写个 if-else 渲染不就行了?”
    不行!因为 Router 帮你保持了 UI 和 URL 的同步

    • 比如你在京东看到一个商品的详情页,复制 URL 发给朋友,朋友打开后看到的必须是同一个商品,而不是首页。React Router 确保了 URL 变了,UI 跟着变;UI 变了,URL 也跟着变。
  3. 历史记录管理 (Time Travel)
    它自动帮你处理了浏览器的“后退”和“前进”按钮。如果没有它,你在单页应用里点后退,可能直接就退出了整个网站,用户绝对会抓狂。

适用场景

React Router 几乎是 React 开发的标准配置,特别是以下场景:

  • 后台管理系统 (Admin Dashboard) :需要侧边栏常驻,只有右侧内容区切换(嵌套路由的绝佳舞台)。
  • 内容型平台 (如掘金、知乎) :需要在列表页、详情页、个人中心之间流畅跳转。
  • SaaS 工具类应用:操作逻辑复杂,需要保持应用状态不丢失。

一句话总结:如果你在写一个 React 应用,并且希望它有多个“页面”,别犹豫,React Router 就是你的必选装备,现在让我们快速入门React Router。


1. 快速上手与基本配置

首先,确保你的项目已经安装了最新版的路由库:

Bash

npm install react-router-dom
# 或者
yarn add react-router-dom

核心组件配置

在 v6 中,我们依然使用 BrowserRouter 包裹应用,但最大的变化在于路由的定义方式:

  1. Switch 已死,Routes 当立:不再使用 Switch,改用 <Router>
  2. component 属性被弃用:现在统一使用 element 属性,并且传递的是组件实例(即 <Home />),而不是组件类或函数名。

App.js 标准配置示例

Jsx

import React from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import NotFound from './pages/NotFound';

function App() {
  return (
    <BrowserRouter>
      {/* Routes 替代了 Switch */}
      <Routes>
        {/* element 属性替代了 component,注意这里传的是 JSX */}
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        
        {/* v6 移除了 exact,默认就是精确匹配 */}
        
        {/* 404 页面配置,path="*" 匹配所有未定义的路径 */}
        <Route path="*" element={<NotFound />} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;

2. 导航与跳转

页面跳转是路由的灵魂。v6 在声明式导航和编程式导航上都有优化。

声明式导航:Link 与 NavLink

普通的跳转使用 ,这和以前一样:

Jsx

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

<Link to="/about">去关于页</Link>

重点:NavLink 的高亮样式
在 v5 中我们使用 activeClassName,但在 v6 中这个属性被移除了。className 现在接收一个函数,通过 isActive 参数来判断状态:

Jsx

import { NavLink } from 'react-router-dom';
import './Nav.css'; // 假设你定义了 .active 类

function NavBar() {
  return (
    <nav>
      <NavLink 
        to="/" 
        className={({ isActive }) => isActive ? "nav-item active" : "nav-item"}
      >
        首页
      </NavLink>
      <NavLink 
        to="/about"
        className={({ isActive }) => isActive ? "nav-item active" : "nav-item"}
      >
        关于
      </NavLink>
    </nav>
  );
}

编程式导航:useNavigate (再见 useHistory)

这是很多老手最不习惯的地方:useHistory 没了!现在使用 useNavigate Hook。

Jsx

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

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

  const handleLogin = () => {
    // 登录逻辑...
    
    // 1. 普通跳转
    navigate('/dashboard');
    
    // 2. 替换路由 (不留历史记录,类似 history.replace)
    // navigate('/dashboard', { replace: true });
    
    // 3. 传入数字实现前进/后退
    // navigate(-1); // 后退一步
  };

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

3. 进阶路由:动态与嵌套

动态路由与参数获取

配置带参数的路径非常简单:

Jsx

// 路由配置
<Route path="/article/:id" element={<ArticleDetail />} />

在组件中获取参数,依然使用 useParams Hook:

Jsx

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

function ArticleDetail() {
  // 获取 URL 中的 id 参数
  const { id } = useParams();
  
  return <h1>正在阅读文章 ID: {id}</h1>;
}

嵌套路由与 Outlet (核心特性)

在后台管理系统中,我们经常需要“侧边栏 + 顶部栏 + 内容区”的布局。v6 引入了  组件,让嵌套路由的实现变得异常丝滑。

核心概念: 就像一个占位符,告诉 React Router:“子路由的内容就渲染在这里!”

1. 配置嵌套路由结构:

Jsx

// App.js
<Routes>
  <Route path="/" element={<Home />} />
  
  {/* 父路由:/admin */}
  <Route path="/admin" element={<AdminLayout />}>
    {/* 子路由:/admin/users */}
    <Route path="users" element={<UserList />} />
    {/* 子路由:/admin/settings */}
    <Route path="settings" element={<Settings />} />
  </Route>
</Routes>

2. 在父组件中放置 Outlet:

Jsx

// AdminLayout.js
import { Outlet, Link } from 'react-router-dom';

function AdminLayout() {
  return (
    <div className="layout">
      <aside>
        <Link to="users">用户管理</Link>
        <Link to="settings">系统设置</Link>
      </aside>
      
      <main>
        {/*  见证奇迹的时刻:子路由组件将渲染在这里  */}
        <Outlet />
      </main>
    </div>
  );
}

4. 路由守卫与权限控制

v5 中我们要么写  包装器,要么用 render 属性。v6 不支持 render 属性了

最佳实践:使用**高阶组件(Wrapper Component)**配合  组件。

实现 RequireAuth 组件

我们需要创建一个组件,用来拦截未登录的访问:

Jsx

// components/RequireAuth.js
import { Navigate, useLocation } from 'react-router-dom';

function RequireAuth({ children }) {
  const isLogin = localStorage.getItem('token'); // 模拟鉴权逻辑
  const location = useLocation();

  if (!isLogin) {
    // 未登录,强制跳转到登录页
    // replace: true 确保用户登录后点后退不会又回到受保护页面
    // state: 保存当前位置,登录后可以跳回来
    return <Navigate to="/login" state={{ from: location }} replace />;
  }

  // 已登录,渲染子组件
  return children;
}

export default RequireAuth;

在路由中使用

用 RequireAuth 包裹需要保护的页面组件:

Jsx

// App.js
<Routes>
  <Route path="/login" element={<Login />} />
  
  <Route 
    path="/dashboard" 
    element={
      <RequireAuth>
        <Dashboard />
      </RequireAuth>
    } 
  />
</Routes>

这样写逻辑解耦,清晰明了!


5. 常用 Hooks 补充:处理查询参数

在 v6 中,获取 URL 上的查询参数(如 ?q=react&sort=asc)推荐使用 useSearchParams。它的用法和 useState 非常像。

Jsx

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

function SearchPage() {
  const [searchParams, setSearchParams] = useSearchParams();
  
  // 获取参数
  const query = searchParams.get('q'); 

  return (
    <div>
      <p>搜索关键词: {query}</p>
      <button onClick={() => setSearchParams({ q: 'vue' })}>
        改为搜索 Vue
      </button>
    </div>
  );
}

6. 总结:v5 迁移 v6 速查表

为了方便老玩家迁移,我整理了这张核心 API 对照表:

功能React Router v5React Router v6备注
路由容器<Switch><Routes>必须使用
定义路由<Route component={Home} /><Route element={<Home />} />传组件实例 (JSX)
重定向<Redirect to="/home" /><Navigate to="/home" />组件名变更
导航 HookuseHistoryuseNavigateAPI 完全重设计
当前路由样式activeClassNameclassName={(isActive) => ...}变为函数式控制
嵌套路由手动配置路径<Outlet /> 组件更加声明式和简洁
精确匹配需要 exact 属性默认精确匹配不再需要 exact

结语

React Router v6 的设计理念是Composition(组合)Simplification(简化) 。虽然刚开始从 v5 迁移过来会有点不习惯,但一旦上手,你会发现它的 API 设计更加符合 React Hooks 的心智模型,嵌套路由的处理也更加优雅,通过本章的学习,您不仅掌握了 React Router 的基本概念和安装方法,还学会了如何配置和导航路由,实现了动态路由和嵌套路由,以及如何使用路由守卫和权限控制确保应用的安全性和用户体验。这些技能将帮助您在实际项目中构建结构清晰、功能完善的路由系统,提高应用的可用性和安全性。希望这些内容对您在实际项目中的开发工作有所帮助。