React Router 使用教程:构建现代化单页面应用的完整指南
【免费下载链接】react-router 项目地址: https://gitcode.com/gh_mirrors/rea/react-router
前言:为什么需要客户端路由?
在传统网站中,浏览器每次导航都需要向服务器请求完整的HTML文档,这会导致页面闪烁和加载延迟。React Router 实现了客户端路由(Client Side Routing),允许应用在不重新加载整个页面的情况下更新URL和渲染新UI,从而提供更流畅的用户体验。
通过本教程,你将掌握:
- ✅ React Router 核心概念和组件
- ✅ 嵌套路由和布局管理
- ✅ 数据加载和表单处理
- ✅ 错误边界和加载状态
- ✅ 实战项目开发技巧
一、环境搭建与基础配置
1.1 创建React项目并安装依赖
# 使用Vite创建React项目
npm create vite@latest my-router-app -- --template react
cd my-router-app
# 安装React Router DOM
npm install react-router-dom
# 启动开发服务器
npm run dev
1.2 基础路由配置
// src/main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import './index.css'
// 创建路由配置
const router = createBrowserRouter([
{
path: "/",
element: <div>首页内容</div>,
},
{
path: "/about",
element: <div>关于我们</div>,
},
{
path: "/contact",
element: <div>联系我们</div>,
},
])
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
)
二、核心概念深度解析
2.1 路由匹配机制
React Router 使用**排名路由匹配(Ranked Route Matching)**算法,自动选择最具体的路由:
2.2 嵌套路由架构
// 嵌套路由配置示例
const router = createBrowserRouter([
{
path: "/",
element: <Layout />,
children: [
{
index: true,
element: <Home />,
},
{
path: "dashboard",
element: <Dashboard />,
children: [
{
path: "stats",
element: <Stats />,
},
{
path: "settings",
element: <Settings />,
}
]
},
{
path: "profile",
element: <Profile />,
}
]
}
])
三、核心组件详解
3.1 <Link> 组件:智能导航
import { Link } from 'react-router-dom'
function Navigation() {
return (
<nav>
<Link to="/" relative="route">
首页
</Link>
<Link to="/about" preventScrollReset>
关于
</Link>
<Link to="/contact" state={{ from: 'nav' }}>
联系
</Link>
</nav>
)
}
Link组件属性对比表:
| 属性 | 类型 | 说明 | 默认值 |
|---|---|---|---|
to | string/object | 目标路径 | 必填 |
replace | boolean | 替换历史记录 | false |
state | any | 传递的状态数据 | null |
preventScrollReset | boolean | 阻止滚动重置 | false |
relative | 'route'/'path' | 相对解析方式 | 'route' |
3.2 <NavLink> 组件:活动状态管理
import { NavLink } from 'react-router-dom'
function NavBar() {
return (
<nav>
<NavLink
to="/"
style={({ isActive, isPending }) => ({
color: isActive ? 'red' : 'black',
opacity: isPending ? 0.5 : 1
})}
className={({ isActive }) =>
isActive ? 'active-link' : 'normal-link'
}
>
首页
</NavLink>
</nav>
)
}
3.3 <Outlet> 组件:嵌套内容渲染
function Layout() {
return (
<div className="layout">
<header>网站头部</header>
<main>
<Outlet /> {/* 子路由内容在这里渲染 */}
</main>
<footer>网站底部</footer>
</div>
)
}
四、数据加载与状态管理
4.1 Loader:路由数据预加载
// 用户列表页面
import { useLoaderData } from 'react-router-dom'
export async function loader() {
const response = await fetch('/api/users')
if (!response.ok) {
throw new Response('用户数据加载失败', { status: 500 })
}
return response.json()
}
function UsersPage() {
const users = useLoaderData()
return (
<div>
<h1>用户列表</h1>
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
)
}
4.2 Action:表单数据处理
// 用户创建表单
import { Form, redirect } from 'react-router-dom'
export async function action({ request }) {
const formData = await request.formData()
const userData = Object.fromEntries(formData)
const response = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(userData)
})
if (!response.ok) {
throw new Response('用户创建失败', { status: 400 })
}
return redirect('/users')
}
function CreateUserForm() {
return (
<Form method="post">
<input name="name" placeholder="用户名" required />
<input name="email" type="email" placeholder="邮箱" required />
<button type="submit">创建用户</button>
</Form>
)
}
4.3 数据流管理架构
五、错误处理与加载状态
5.1 错误边界配置
// 错误页面组件
import { useRouteError, isRouteErrorResponse } from 'react-router-dom'
export function ErrorBoundary() {
const error = useRouteError()
if (isRouteErrorResponse(error)) {
return (
<div>
<h1>{error.status} {error.statusText}</h1>
<p>{error.data}</p>
</div>
)
}
return (
<div>
<h1>意外错误</h1>
<p>{error.message || '未知错误发生'}</p>
</div>
)
}
// 在路由配置中使用
const router = createBrowserRouter([
{
path: "/",
element: <Root />,
errorElement: <ErrorBoundary />,
children: [
// 子路由配置
]
}
])
5.2 加载状态管理
import { useNavigation } from 'react-router-dom'
function GlobalLoader() {
const navigation = useNavigation()
return (
<div className={`loader ${navigation.state !== 'idle' ? 'loading' : ''}`}>
{navigation.state === 'loading' && '页面加载中...'}
{navigation.state === 'submitting' && '表单提交中...'}
</div>
)
}
// 骨架屏实现
function UserSkeleton() {
return (
<div className="skeleton">
<div className="skeleton-avatar"></div>
<div className="skeleton-name"></div>
<div className="skeleton-email"></div>
</div>
)
}
六、高级特性与最佳实践
6.1 延迟加载与代码分割
import { lazy } from 'react'
// 使用React.lazy进行组件懒加载
const Dashboard = lazy(() => import('./Dashboard'))
const Settings = lazy(() => import('./Settings'))
// 路由配置中使用
const router = createBrowserRouter([
{
path: "/",
element: <Layout />,
children: [
{
path: "dashboard",
element: (
<Suspense fallback={<div>加载中...</div>}>
<Dashboard />
</Suspense>
)
},
{
path: "settings",
element: (
<Suspense fallback={<div>加载中...</div>}>
<Settings />
</Suspense>
)
}
]
}
])
6.2 搜索参数管理
import { useSearchParams } from 'react-router-dom'
function SearchFilter() {
const [searchParams, setSearchParams] = useSearchParams()
const query = searchParams.get('q') || ''
const category = searchParams.get('category') || 'all'
const handleSearch = (newQuery) => {
setSearchParams(prev => {
prev.set('q', newQuery)
return prev
})
}
const handleCategoryChange = (newCategory) => {
setSearchParams(prev => {
prev.set('category', newCategory)
return prev
})
}
return (
<div>
<input
value={query}
onChange={(e) => handleSearch(e.target.value)}
placeholder="搜索..."
/>
<select
value={category}
onChange={(e) => handleCategoryChange(e.target.value)}
>
<option value="all">全部</option>
<option value="tech">技术</option>
<option value="design">设计</option>
</select>
</div>
)
}
6.3 路由守卫与权限控制
// 认证保护组件
import { redirect } from 'react-router-dom'
export async function requireAuth(request) {
const isLoggedIn = localStorage.getItem('isLoggedIn')
const url = new URL(request.url)
if (!isLoggedIn) {
throw redirect(`/login?redirectTo=${encodeURIComponent(url.pathname)}`)
}
return null
}
// 在loader中使用
export async function dashboardLoader({ request }) {
await requireAuth(request)
// 加载仪表板数据
return fetch('/api/dashboard')
}
// 保护路由配置
const router = createBrowserRouter([
{
path: "/login",
element: <LoginPage />,
},
{
path: "/",
element: <Layout />,
children: [
{
path: "dashboard",
element: <Dashboard />,
loader: dashboardLoader, // 受保护的loader
}
]
}
])
七、实战项目:任务管理系统
7.1 项目结构设计
src/
├── components/
│ ├── Layout.jsx
│ ├── TaskList.jsx
│ └── TaskForm.jsx
├── routes/
│ ├── root.jsx
│ ├── tasks.jsx
│ ├── task.jsx
│ └── error-page.jsx
├── utils/
│ └── api.js
└── main.jsx
7.2 完整路由配置
// main.jsx
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import Layout, { layoutLoader } from './routes/root'
import Tasks, { tasksLoader, tasksAction } from './routes/tasks'
import Task, { taskLoader, taskAction } from './routes/task'
import ErrorPage from './routes/error-page'
const router = createBrowserRouter([
{
path: "/",
element: <Layout />,
errorElement: <ErrorPage />,
loader: layoutLoader,
children: [
{
index: true,
element: <Tasks />,
loader: tasksLoader,
action: tasksAction,
},
{
path: "tasks/:taskId",
element: <Task />,
loader: taskLoader,
action: taskAction,
},
{
path: "tasks/:taskId/edit",
element: <TaskForm />,
loader: taskLoader,
action: taskAction,
},
{
path: "tasks/new",
element: <TaskForm />,
action: tasksAction,
}
]
}
])
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
)
7.3 性能优化策略
路由配置优化表:
| 优化策略 | 实现方式 | 效果 | 适用场景 |
|---|---|---|---|
| 代码分割 | lazy() + Suspense | 减少初始包大小 | 大型应用 |
| 数据预加载 | loader 函数 | 并行数据加载 | 数据密集型页面 |
| 缓存策略 | shouldRevalidate | 减少重复请求 | 频繁访问页面 |
| 错误边界 | errorElement | 优雅降级 | 所有路由 |
| 骨架屏 | defer + Await | 提升用户体验 | 数据加载页面 |
八、常见问题与解决方案
8.1 路由匹配问题
问题: 动态路由参数无法正确解析 解决方案:
// 正确配置动态路由
<Route path="users/:userId/posts/:postId" />
// 在组件中获取参数
function UserPost() {
const { userId, postId } = useParams()
// 使用参数...
}
8.2 滚动恢复问题
问题: 页面切换时滚动位置异常 解决方案:
import { ScrollRestoration } from 'react-router-dom'
function App() {
return (
<>
<ScrollRestoration />
{/* 其他内容 */}
</>
)
}
8.3 表单重复提交问题
问题: 用户多次点击提交按钮 解决方案:
function SubmitButton() {
const navigation = useNavigation()
const isSubmitting = navigation.state === 'submitting'
return (
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? '提交中...' : '提交'}
</button>
)
}
九、总结与最佳实践
9.1 核心原则
- 约定优于配置:遵循React Router的约定式路由设计
- 错误处理优先:为所有路由配置错误边界
- 数据驱动UI:充分利用loader和action管理数据流
- 用户体验至上:实现加载状态和骨架屏
9.2 性能优化清单
- 使用代码分割减少初始包大小
- 配置适当的缓存策略
- 实现骨架屏提升感知性能
- 优化图片和静态资源加载
9.3 扩展学习资源
- React Router官方文档:深入理解高级特性
- Web平台API:Request、Response、FormData等
- 现代JavaScript:Async/Await、Promise等特性
- HTTP协议:理解RESTful API设计原则
通过本教程,你已经掌握了React Router的核心概念和实战技巧。现在可以开始构建高效、用户体验优秀的现代化单页面应用了!
【免费下载链接】react-router 项目地址: https://gitcode.com/gh_mirrors/rea/react-router
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



