它的核心思想是:一切皆资源,但资源的获取和切换,由前端 JavaScript 来控制,不再依赖后端服务器的实时响应。
具体来说,前端路由利用浏览器提供的特性,在不刷新页面的前提下,去改变浏览器地址栏的 URL ,并根据 URL 的变化,动态地去渲染对应的页面组件。
react-router-dom 是 React 官方推荐的 Web 应用路由库
渲染规则: 除了导航组件(Link/NavLink)会渲染外,只有匹配当前 URL 的 Route element 才会渲染。
| 组件类别 | 核心组件 | 主要作用 |
|---|---|---|
| 路由器 (Routers) | BrowserRouter, HashRouter | 相当于整个应用的"地基",提供路由环境。 负责: 1. 监听 URL 的变化(无论是 # 还是 History API) 2.把当前 URL 信息存储到 React 的上下文中,让子组件都能访问到 |
| 路由匹配器 (Matchers) | Routes, Route, Switch | 根据当前 URL,决定"显示哪个组件"。 |
| 导航组件 (Navigation) | Link, NavLink, Navigate | 提供让用户"触发路由跳转"的方式。 |
路由
在 React 应用中,我们通常使用 react-router-dom 这个库来实现前端路由。它提供了两种路由模式:
-
HashRouter:
这种模式利用 URL 中的
#(锚点)符号。例如:http://example.com/#/home。#及其后面的部分被称为hash。改变
hash值,浏览器并不会向服务器发送请求,也就不会刷新页面。同时,浏览器提供了hashchange事件,我们可以监听这个事件,当hash改变时,获取最新的hash值,然后渲染对应的页面组件。 -
BrowserRouter:
三种方法
1. pushState(state, title, url)
-
操作对象:浏览器历史记录栈
-
行为:在栈顶添加一条新记录
-
URL 变化:地址栏立即变为新 URL
-
页面刷新:否
-
触发 popstate:否
-
使用场景:用户主动触发导航(如点击链接、表单提交后的跳转)
2.replaceState(state, title, url)
-
操作对象:浏览器历史记录栈
-
行为:用新记录替换栈顶的当前记录
-
URL 变化:地址栏立即变为新 URL
-
页面刷新:否
-
触发
popstate:否 -
使用场景:不希望用户后退到当前页面的场景(如登录成功后替换登录页)
3.popState 事件
-
本质:浏览器原生事件
-
触发时机:历史记录条目发生变化时(用户点击前进/后退按钮,或调用
back()、
forward()、go()方法) -
不触发时机:调用
pushState()或replaceState()时 -
作用:作为监听器,通知 JavaScript 环境"当前激活的历史记录已改变"
-
数据获取:通过
event.state读取与该记录关联的状态对象
-
路由匹配器
-
Routes:遍历子 Route,只渲染第一个匹配的组件(独占匹配)
-
Route:定义路由规则,path 是匹配条件,element 是要渲染的组件
<Routes>
<Route path="/users" element={<UserList />} />
<Route path="/users/:id" element={<UserDetail />} />
</Routes>
翻译:当url为path的时候,将页面渲染为element的组件
如果 URL 是 /users/123:
-
第一个
path="/users"不匹配(因为多了/123) -
第二个
path="/users/:id"匹配 ✅ -
只渲染
UserDetail
导航组件
-
<Link>基础导航组件,点击后跳转到指定路径,渲染为<a>标签。 -
<NavLink>是<Link>的增强版,能根据当前 URL 自动匹配并添加高亮样式(active类),适合导航菜单。 -
<Navigate>不是点击触发的链接,而是渲染即跳转,用于条件性重定向(如登录状态判断后自动跳转)。<Link to="/about">关于我们</Link><NavLink to="/" className={({ isActive }) => isActive ? 'active-link' : ''}> 首页 </NavLink> <NavLink to="/about" className={({ isActive }) => isActive ? 'active-link' : ''}> 关于 </NavLink> <NavLink to="/contact" className={({ isActive }) => isActive ? 'active-link' : ''}> 联系 </NavLink>.active-link { color: red; /* 激活时文字变红 */ font-weight: bold; /* 激活时加粗 */ border-bottom: 2px solid red; /* 激活时加下划线 */ }
你在 /about 页面:"关于"按钮自动变红加粗(因为匹配)
你在 /contact 页面:"联系"按钮自动变红加粗
你在 / 页面:"首页"按钮自动变红加粗
{isLoggedIn ? <Dashboard /> : <Navigate to="/login" />}//进行登录状态的判断
<Navigate>
基本用法
import { Navigate } from 'react-router-dom'
<Navigate to="/home" replace />
核心属性:
to 必填。表示目标路径,如 "/home" 或 { pathname: "/home" }
replace 非必填。表示是否替换历史记录,默认 false
state 非必填。表示传递状态数据到目标页面
动态路由
动态路由就是在路由路径中使用占位符(参数) ,让一个路由规则能匹配一类 URL,而不是一个固定的 URL
一般语法:
<Route path="/user/:id" element={<UserProfile />} />
// :id 是占位符,匹配 /user/ 后面的任意值
// 一个路由规则可以匹配无数个不同的 URL
在 React Router 中,只要路径中以冒号 : 开头的部分,都是占位符(动态参数)
获取参数:
useParams 是 React Router 提供的钩子函数,用于获取动态路由中的参数。
基本用法:
import { useParams } from 'react-router-dom'
function UserProfile() {
const { id } = useParams()
return <div>用户ID:{id}</div>
}
路由配置:
<Route path="/user/:id" element={<UserProfile />} />
嵌套路由
嵌套路由就是在父组件中定义子路由,实现布局共享。比如,用户中心有侧边栏,点击不同选项只切换右侧内容,侧边栏保持不变。
核心组件:Outlet
<Outlet /> 是子路由的占位符,父组件中放它,子组件就会渲染在这里。
import { Outlet } from 'react-router-dom'
function UserLayout() {
return (
<div>
<h1>用户中心</h1>
<nav>
<Link to="/user/profile">个人资料</Link>
<Link to="/user/settings">设置</Link>
</nav>
<Outlet /> {/* 子路由渲染在这里 */}
</div>
)
}
// 路由配置
<Routes>
<Route path="/user" element={<UserLayout />}>
<Route path="profile" element={<Profile />} />
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
在嵌套路由中,匹配多个 Route 是它的核心设计
/user/profile 这个 URL 包含了两层信息:
- 第一层
/user:告诉我们"这是用户中心页面"(需要渲染UserLayout这个框架)。 - 第二层
/profile:告诉我们"当前在用户中心的个人资料页"(需要把Profile这个具体内容,渲染到框架的Outlet里)。
路由重定向
路由重定向就是当用户访问一个旧地址时,自动将其跳转到新地址。比如页面搬家,网站改版或者登录拦截等等。
两种重定向方式
1:<Navigate> 组件(声明式)
import { Navigate } from 'react-router-dom'
function App() {
return (
<Routes>
{/* 访问 /about 时自动跳转到 /company */}
<Route path="/about" element={<Navigate to="/company" replace />} />
<Route path="/company" element={<Company />} />
</Routes>
)
}
2:useNavigate 钩子(编程式)
import { useNavigate } from 'react-router-dom'
function LoginPage() {
const navigate = useNavigate()
const handleLogin = () => {
// 登录成功后跳转到首页
navigate('/')
}
}
404处理(必写!)
用户可能输入任何 URL,你无法控制。如果不写 404,用户访问不存在的页面时,会看到一片空白,体验极差。
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
const NotFound = () => {
let navigate = useNavigate();
useEffect(() => {
// 一个简单的定时器,3秒后跳转回首页
const timer = setTimeout(() => {
navigate('/');
}, 3000);
// 在组件卸载时清理定时器,是一个好的实践
return () => clearTimeout(timer);
}, [navigate]); // 依赖项中加入 navigate
return (
<>
<h1>404 - 页面未找到</h1>
<p>3秒后将自动返回首页</p>
</>
);
};
export default NotFound;