当前位置: 首页 > news >正文

React从基础入门到高级实战:React 核心技术 - React Router:路由管理

React Router:路由管理

在现代 Web 应用开发中,路由管理 是构建多页面或单页应用(SPA)的核心技术之一。React Router 是 React 生态中最受欢迎的路由管理库,它为开发者提供了强大的工具来实现页面导航、动态路由和权限控制等功能。React Router v6 是其最新版本,相较于之前的版本,它带来了更简洁的 API、更灵活的嵌套路由支持以及更强大的导航工具,显著提升了开发体验。

本文专为希望实现多页面应用的开发者设计,内容涵盖 React Router v6 的安装与配置、核心路由组件、动态路由、导航方式、嵌套路由和路由守卫等核心主题。我们将通过一个简单的电商网站案例(包含首页、商品列表和详情页)以及一个练习任务(实现受保护的用户中心),帮助你深入掌握 React Router v6 的核心技能。


文章目标

  • 理解 React Router v6 的安装和基本配置。
  • 掌握核心路由组件(如 <Routes><Route>)的使用。
  • 实现动态路由和查询参数的处理。
  • 学会使用导航组件(<Link><NavLink>)和 Hook(useNavigate)。
  • 探索嵌套路由和路由守卫的实现方法。
  • 通过电商网站案例和练习任务巩固所学知识。

1. React Router v6 简介

1.1 什么是 React Router?

React Router 是一个专为 React 应用设计的路由管理库,它允许开发者根据 URL 动态渲染不同的组件,从而实现页面导航和切换。在单页应用(SPA)中,React Router 通过客户端路由管理页面的显示,无需刷新浏览器即可实现流畅的页面跳转。它是 React 生态中不可或缺的一部分,尤其适用于需要多页面结构的复杂应用。

1.2 为什么选择 React Router v6?

React Router v6 是 React Router 的最新版本,相较于 v5 和更早的版本,它引入了许多重要改进和新特性:

  • 更简洁的 API:移除了 <Switch> 组件,改为使用 <Routes><Route> 的组合,语法更直观。
  • 更强大的嵌套路由:通过 <Outlet> 组件实现灵活的布局管理。
  • 动态路由增强:支持相对路径和更便捷的参数化路由。
  • 内置导航 Hook:提供了 useNavigateuseParams 等 Hook,简化路由操作。
  • 性能优化:路由匹配和渲染更加高效。

这些新特性使得 React Router v6 成为 2025 年及未来构建现代 Web 应用的首选工具,尤其是在 React 19 的新特性(如 Server Components)逐渐普及的背景下。


2. 安装与配置 React Router v6

2.1 安装

在 React 项目中安装 React Router v6,只需运行以下命令:

npm install react-router-dom@6

注意:确保指定版本 @6,以避免安装旧版本或其他不兼容的版本。

2.2 基本配置

React Router v6 使用 <BrowserRouter> 作为路由容器,通常在应用的根组件中进行配置。<BrowserRouter> 利用 HTML5 History API 管理路由,支持干净的 URL(如 /about 而不是 #/about)。

代码示例

// main.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';ReactDOM.createRoot(document.getElementById('root')).render(<BrowserRouter><App /></BrowserRouter>
);
  • <BrowserRouter>:最常用的路由容器,适合大多数 Web 应用。
  • 其他路由器选项
    • <HashRouter>:使用 URL 的 # 部分管理路由,适合静态文件部署。
    • <MemoryRouter>:将路由存储在内存中,适用于测试或服务器端渲染(SSR)场景。

App 组件中,我们将定义具体的路由规则。


3. 核心路由组件

React Router v6 的核心组件包括 <Routes><Route>,它们共同定义了应用的路由结构。

3.1 <Routes><Route>

  • <Routes>:路由容器的根组件,用于包裹所有 <Route>
  • <Route>:定义单个路由规则,通过 path 属性匹配 URL,通过 element 属性指定渲染的组件。

代码示例

// App.jsx
import { Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import NotFound from './pages/NotFound';function App() {return (<Routes><Route path="/" element={<Home />} /><Route path="/about" element={<About />} /><Route path="*" element={<NotFound />} /></Routes>);
}
  • path="/": 匹配根路径,渲染 Home 组件。
  • path="/about": 匹配 /about 路径,渲染 About 组件。
  • path="*": 通配符,匹配所有未定义的路径,渲染 NotFound 组件(404 页面)。

v6 新特性:相比 v5 的 <Switch><Routes> 更加智能,能够自动匹配最佳路由,并支持嵌套路由的优化。

3.2 动态路由

动态路由允许根据 URL 中的参数渲染不同的内容。例如,/product/1/product/2 可以渲染同一个组件,但显示不同的商品详情。

代码示例

// App.jsx
import { Route } from 'react-router-dom';
import ProductDetail from './pages/ProductDetail';function App() {return (<Routes><Route path="/product/:id" element={<ProductDetail />} /></Routes>);
}
  • :id:动态参数,表示 URL 中的变量部分。
  • 示例 URL:/product/1 会将 id 设置为 "1"

ProductDetail 组件中,使用 useParams Hook 获取参数:

// pages/ProductDetail.jsx
import { useParams } from 'react-router-dom';function ProductDetail() {const { id } = useParams();return <h1>商品 ID: {id}</h1>;
}
  • useParams:返回一个对象,包含所有动态参数。

3.3 查询参数

查询参数通过 URL 的 ?key=value 形式传递,常用于筛选、搜索等场景。React Router v6 提供了 useSearchParams Hook 来处理查询参数。

代码示例

// pages/ProductList.jsx
import { useSearchParams } from 'react-router-dom';function ProductList() {const [searchParams, setSearchParams] = useSearchParams();const category = searchParams.get('category');return (<div><h1>商品列表 - {category || '全部'}</h1><button onClick={() => setSearchParams({ category: 'electronics' })}>筛选电子产品</button></div>);
}
  • useSearchParams:返回一个数组,包含当前查询参数对象和更新函数。
  • searchParams.get('category'):获取 category 参数的值。
  • setSearchParams:更新 URL 的查询参数,例如点击按钮后 URL 变为 /products?category=electronics

4. 导航:Link、NavLink 与 useNavigate

导航是路由管理的核心功能之一,React Router v6 提供了多种方式来实现页面跳转。

4.1 <Link>

<Link> 组件用于创建导航链接,点击时跳转到指定路径,避免页面刷新。

代码示例

import { Link } from 'react-router-dom';function Navbar() {return (<nav><Link to="/">首页</Link> |{' '}<Link to="/about">关于我们</Link></nav>);
}
  • to 属性:指定跳转的目标路径。
  • <Link> 渲染为 <a> 标签,但通过 React Router 内部机制实现客户端导航。

4.2 <NavLink>

<NavLink><Link> 的增强版,可以根据当前路径动态调整样式,例如高亮当前导航项。

代码示例

import { NavLink } from 'react-router-dom';function Navbar() {return (<nav><NavLinkto="/"className={({ isActive }) => (isActive ? 'active' : '')}>首页</NavLink>{' '}|{' '}<NavLinkto="/about"className={({ isActive }) => (isActive ? 'active' : '')}>关于我们</NavLink></nav>);
}
  • className:接受一个函数,参数 isActive 表示当前路径是否匹配。
  • 示例 CSS:
.active {color: red;font-weight: bold;
}

4.3 useNavigate Hook

useNavigate Hook 允许在组件内部以编程方式导航,适用于事件驱动的场景(如按钮点击、表单提交)。

代码示例

import { useNavigate } from 'react-router-dom';function Login() {const navigate = useNavigate();const handleLogin = () => {// 模拟登录逻辑navigate('/dashboard');};return <button onClick={handleLogin}>登录</button>;
}
  • navigate('/dashboard'):跳转到 /dashboard
  • navigate(-1):返回上一页,类似浏览器的“后退”按钮。
  • navigate('/path', { replace: true }):替换当前历史记录,而不是添加新记录。

v6 新特性useNavigate 替代了 v5 的 useHistory,API 更直观且功能更强大。


5. 嵌套路由与路由守卫

5.1 嵌套路由

嵌套路由允许在父路由中定义子路由,常用于实现包含公共布局的页面(如导航栏 + 主内容)。

代码示例

// App.jsx
import { Routes, Route, Outlet } from 'react-router-dom';
import Layout from './components/Layout';
import Home from './pages/Home';
import Dashboard from './pages/Dashboard';
import Settings from './pages/Settings';function App() {return (<Routes><Route path="/" element={<Layout />}><Route index element={<Home />} /><Route path="dashboard" element={<Dashboard />} /><Route path="settings" element={<Settings />} /></Route></Routes>);
}// components/Layout.jsx
import { Outlet } from 'react-router-dom';function Layout() {return (<div><nav>导航栏</nav><main><Outlet /> {/* 子路由渲染位置 */}</main></div>);
}
  • <Route path="/" element={<Layout />}>:父路由,渲染 Layout 组件。
  • <Outlet />:子路由的占位符,指定子组件的渲染位置。
  • <Route index>:默认子路由,匹配父路径 / 时渲染。

v6 新特性<Outlet> 替代了 v5 中手动传递 children,嵌套路由更加简洁。

5.2 路由守卫

路由守卫用于保护某些路由,确保用户在访问受限页面前满足特定条件(如已登录)。React Router v6 没有内置的守卫组件,但可以通过自定义组件实现。

实现方式

import { Navigate, useLocation } from 'react-router-dom';function ProtectedRoute({ children }) {const isAuthenticated = false; // 模拟认证状态const location = useLocation();if (!isAuthenticated) {return <Navigate to="/login" state={{ from: location }} replace />;}return children;
}// 使用
<Routepath="/dashboard"element={<ProtectedRoute><Dashboard /></ProtectedRoute>}
/>
  • ProtectedRoute:检查认证状态的自定义组件。
  • <Navigate>:未认证时重定向到 /login
  • state={{ from: location }}:记录来源路径,登录后可返回。

6. 实践案例:电商网站

我们将通过一个简单的电商网站案例,综合应用以上知识。网站包含以下页面:

  • 首页:欢迎页面。
  • 商品列表:展示商品,支持筛选。
  • 商品详情:根据商品 ID 显示详情。

6.1 项目结构

src/
├── pages/
│   ├── Home.jsx
│   ├── ProductList.jsx
│   ├── ProductDetail.jsx
├── components/
│   ├── Navbar.jsx
├── App.jsx
├── main.jsx

6.2 路由配置

// App.jsx
import { Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import ProductList from './pages/ProductList';
import ProductDetail from './pages/ProductDetail';
import Navbar from './components/Navbar';function App() {return (<div><Navbar /><Routes><Route path="/" element={<Home />} /><Route path="/products" element={<ProductList />} /><Route path="/product/:id" element={<ProductDetail />} /></Routes></div>);
}

6.3 导航栏

// components/Navbar.jsx
import { NavLink } from 'react-router-dom';function Navbar() {return (<nav><NavLink to="/" className={({ isActive }) => (isActive ? 'active' : '')}>首页</NavLink>{' '}|{' '}<NavLinkto="/products"className={({ isActive }) => (isActive ? 'active' : '')}>商品列表</NavLink></nav>);
}

6.4 首页

// pages/Home.jsx
function Home() {return <h1>欢迎来到电商网站</h1>;
}

6.5 商品列表

// pages/ProductList.jsx
import { useSearchParams } from 'react-router-dom';function ProductList() {const [searchParams, setSearchParams] = useSearchParams();const category = searchParams.get('category');const products = [{ id: 1, name: '手机', category: 'electronics' },{ id: 2, name: '书籍', category: 'books' },];const filteredProducts = category? products.filter((p) => p.category === category): products;return (<div><h1>商品列表 - {category || '全部'}</h1><button onClick={() => setSearchParams({ category: 'electronics' })}>电子产品</button><button onClick={() => setSearchParams({ category: 'books' })}>书籍</button><button onClick={() => setSearchParams({})}>全部</button><ul>{filteredProducts.map((product) => (<li key={product.id}><a href={`/product/${product.id}`}>{product.name}</a></li>))}</ul></div>);
}

6.6 商品详情

// pages/ProductDetail.jsx
import { useParams, useNavigate } from 'react-router-dom';function ProductDetail() {const { id } = useParams();const navigate = useNavigate();const products = {1: { name: '手机', price: 2999 },2: { name: '书籍', price: 59 },};const product = products[id] || { name: '未知商品', price: 0 };return (<div><h1>{product.name}</h1><p>价格: ¥{product.price}</p><button onClick={() => navigate('/products')}>返回列表</button></div>);
}

这个案例展示了动态路由(/product/:id)、查询参数(筛选商品)和导航(<NavLink>useNavigate)的实际应用。


7. 练习:添加受保护的用户中心

现在,请尝试为电商网站添加一个受保护的 用户中心,包含以下要求:

  • 创建 /user 路由,渲染 UserCenter 组件。
  • 使用 ProtectedRoute 保护该路由,仅允许已登录用户访问。
  • UserCenter 中添加一个嵌套路由 /user/profile,渲染 Profile 组件。

参考实现

7.1 更新路由配置
// App.jsx
import { Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import ProductList from './pages/ProductList';
import ProductDetail from './pages/ProductDetail';
import UserCenter from './pages/UserCenter';
import Profile from './pages/Profile';
import ProtectedRoute from './components/ProtectedRoute';
import Navbar from './components/Navbar';function App() {return (<div><Navbar /><Routes><Route path="/" element={<Home />} /><Route path="/products" element={<ProductList />} /><Route path="/product/:id" element={<ProductDetail />} /><Routepath="/user"element={<ProtectedRoute><UserCenter /></ProtectedRoute>}><Route path="profile" element={<Profile />} /></Route></Routes></div>);
}
7.2 实现 ProtectedRoute
// components/ProtectedRoute.jsx
import { Navigate } from 'react-router-dom';function ProtectedRoute({ children }) {const isAuthenticated = localStorage.getItem('token'); // 模拟认证return isAuthenticated ? children : <Navigate to="/login" replace />;
}
7.3 用户中心
// pages/UserCenter.jsx
import { Link, Outlet } from 'react-router-dom';function UserCenter() {return (<div><h1>用户中心</h1><nav><Link to="/user/profile">编辑资料</Link></nav><Outlet /> {/* 渲染子路由 */}</div>);
}
7.4 个人资料页
// pages/Profile.jsx
function Profile() {return <h2>个人资料页面</h2>;
}
7.5 更新导航栏
// components/Navbar.jsx
import { NavLink } from 'react-router-dom';function Navbar() {return (<nav><NavLink to="/" className={({ isActive }) => (isActive ? 'active' : '')}>首页</NavLink>{' '}|{' '}<NavLinkto="/products"className={({ isActive }) => (isActive ? 'active' : '')}>商品列表</NavLink>{' '}|{' '}<NavLinkto="/user"className={({ isActive }) => (isActive ? 'active' : '')}>用户中心</NavLink></nav>);
}

测试步骤

  1. 未登录时(localStorage.getItem('token') 为 null),访问 /user 会跳转到 /login
  2. 模拟登录(localStorage.setItem('token', '123')),即可访问 /user/user/profile

8. 总结与进阶建议

React Router v6 是一个功能强大且灵活的路由管理工具,通过 <Routes><Route><Link> 等组件以及 useNavigateuseParams 等 Hook,开发者可以轻松实现多页面应用的导航和权限控制。本文通过电商网站案例和用户中心练习,展示了 React Router v6 的核心功能及其新特性(如 <Outlet> 和简化的 API)。

进阶建议

  • 数据加载器(Data Loaders):探索 React Router v6 的数据加载功能,提升页面加载性能。
  • 状态管理集成:结合 Redux 或 Context API,实现更复杂的路由逻辑。

希望这篇教程能为你的 React 开发之旅提供坚实的基础!如果有任何问题,欢迎交流。


以下是一个完整的 React Router v6 电商网站示例代码,供参考:

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>电商网站 - React Router v6</title><script src="https://cdn.jsdelivr.net/npm/react@18/umd/react.development.js"></script><script src="https://cdn.jsdelivr.net/npm/react-dom@18/umd/react-dom.development.js"></script><script src="https://cdn.jsdelivr.net/npm/react-router-dom@6/dist/umd/react-router-dom.development.js"></script><script src="https://cdn.jsdelivr.net/npm/@babel/standalone/babel.min.js"></script><style>nav { margin-bottom: 20px; }.active { color: red; font-weight: bold; }button { margin: 0 5px; }</style>
</head>
<body><div id="root"></div><script type="text/babel">const { BrowserRouter, Routes, Route, Link, NavLink, useParams, useNavigate, useSearchParams, Outlet, Navigate } = ReactRouterDOM;function ProtectedRoute({ children }) {const isAuthenticated = localStorage.getItem('token');return isAuthenticated ? children : <Navigate to="/login" replace />;}function Navbar() {return (<nav><NavLink to="/" className={({ isActive }) => (isActive ? 'active' : '')}>首页</NavLink> |{' '}<NavLink to="/products" className={({ isActive }) => (isActive ? 'active' : '')}>商品列表</NavLink> |{' '}<NavLink to="/user" className={({ isActive }) => (isActive ? 'active' : '')}>用户中心</NavLink></nav>);}function Home() {return <h1>欢迎来到电商网站</h1>;}function ProductList() {const [searchParams, setSearchParams] = useSearchParams();const category = searchParams.get('category');const products = [{ id: 1, name: '手机', category: 'electronics' },{ id: 2, name: '书籍', category: 'books' },];const filteredProducts = category ? products.filter(p => p.category === category) : products;return (<div><h1>商品列表 - {category || '全部'}</h1><button onClick={() => setSearchParams({ category: 'electronics' })}>电子产品</button><button onClick={() => setSearchParams({ category: 'books' })}>书籍</button><button onClick={() => setSearchParams({})}>全部</button><ul>{filteredProducts.map(product => (<li key={product.id}><Link to={`/product/${product.id}`}>{product.name}</Link></li>))}</ul></div>);}function ProductDetail() {const { id } = useParams();const navigate = useNavigate();const products = {1: { name: '手机', price: 2999 },2: { name: '书籍', price: 59 },};const product = products[id] || { name: '未知商品', price: 0 };return (<div><h1>{product.name}</h1><p>价格: ¥{product.price}</p><button onClick={() => navigate('/products')}>返回列表</button></div>);}function UserCenter() {return (<div><h1>用户中心</h1><nav><Link to="/user/profile">编辑资料</Link></nav><Outlet /></div>);}function Profile() {return <h2>个人资料页面</h2>;}function Login() {const navigate = useNavigate();const handleLogin = () => {localStorage.setItem('token', '123');navigate('/user');};return <button onClick={handleLogin}>登录</button>;}function App() {return (<div><Navbar /><Routes><Route path="/" element={<Home />} /><Route path="/products" element={<ProductList />} /><Route path="/product/:id" element={<ProductDetail />} /><Route path="/login" element={<Login />} /><Route path="/user" element={<ProtectedRoute><UserCenter /></ProtectedRoute>}><Route path="profile" element={<Profile />} /></Route></Routes></div>);}const root = ReactDOM.createRoot(document.getElementById('root'));root.render(<BrowserRouter><App /></BrowserRouter>);</script>
</body>
</html>

运行这段代码,你将得到一个完整的电商网站示例,包含所有功能点。祝你学习愉快!

相关文章:

  • 【操作系统】-4.3.1文件的层次结构
  • 计算机网络技术(二)
  • DAY33 简单神经网络
  • Leetcode 1651. Hopper 公司查询 III
  • 【NIPS 2024】Towards Robust Multimodal Sentiment Analysis with Incomplete Data
  • quill 富文本多张图片排序
  • 大语言模型的完整训练周期从0到1的体系化拆解
  • CS学习网站-geeksforgeeks介绍
  • 历年安徽大学保研上机真题
  • 原生php单元测试
  • Kafka 的日志清理策略:delete 和 compact
  • 决策引擎与规则引擎在交易所业务风控中的建设思路、架构设
  • 历年北京理工大学保研上机真题
  • 使用 Hyperlane 实现 WebSocket广播
  • MIT 6.S081 2020Lab5 lazy page allocation 个人全流程
  • 《技术择时,价值择股》速读笔记
  • [论文品鉴] DeepSeek V3 最新论文 之 MTP
  • 历年北京邮电大学保研上机真题
  • 嵌入式硬件篇---Ne555定时器
  • 私有知识库 Coco AI 实战(七):摄入本地 PDF 文件
  • 繁体企业网站源码/竞价推广价格
  • 淘宝客网站做seo有用吗/百度指数数据分析
  • 做网站-信科网络/注册推广赚钱一个10元
  • 网站建设项目介绍/网站网络排名优化方法
  • 工程项目网站/如何进行搜索引擎的优化
  • 如何安装wordpress到usbwebserver/百度关键词优化方法