· 4 min read
React Router
React
React Router 是 React 生态系统中最流行的路由库,它让单页面应用(SPA)既能保持 URL 与 UI 的同步,又无需页面刷新。这里主要记录 React Router v6 的核心概念和实际用法。
1. 核心组件
React Router v6 提供了几个核心组件来定义和管理路由:
1.1 Router 组件
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
}
注意: v6 使用
<Routes>替代了 v5 的<Switch>,<Route>的component属性改为element属性。
| 组件 | 作用 |
|---|---|
BrowserRouter | 使用 HTML5 History API,支持干净的 URL |
HashRouter | 使用 URL hash 部分,适用于不支持 History API 的环境 |
MemoryRouter | 内存路由,常用于测试 |
1.2 Link 和 NavLink
import { Link, NavLink } from 'react-router-dom';
// 普通链接 - 不会触发页面刷新
<Link to="/about">关于</Link>
// 导航链接 - 可添加激活样式
<NavLink
to="/profile"
className={({ isActive }) => isActive ? 'active' : ''}
>
个人资料
</NavLink>
2. 路由参数
2.1 动态路由参数
通过 :参数名 定义动态路径段:
<Routes>
<Route path="/user/:userId" element={<UserProfile />} />
<Route path="/post/:postId/comments/:commentId" element={<Comment />} />
</Routes>
2.2 获取路由参数
v6 使用 useParams Hook 获取参数:
import { useParams } from 'react-router-dom';
function UserProfile() {
const { userId } = useParams();
return <h1>用户 ID: {userId}</h1>;
}
提示: 相比 v5 的
this.props.match.params,Hook 方式更简洁,适用于函数组件。
3. 编程式导航
3.1 useNavigate Hook
v6 使用 useNavigate 替代 history 对象:
import { useNavigate } from 'react-router-dom';
function LoginButton() {
const navigate = useNavigate();
const handleLogin = () => {
// 登录逻辑...
navigate('/dashboard');
};
return <button onClick={handleLogin}>登录</button>;
}
3.2 导航选项
const navigate = useNavigate();
// 替换当前历史记录
navigate('/new-page', { replace: true });
// 带状态导航
navigate('/user/123', { state: { from: '/login' } });
3.3 获取导航状态
使用 useLocation 获取当前位置信息:
import { useLocation } from 'react-router-dom';
function Breadcrumb() {
const location = useLocation();
// location.pathname = "/user/123"
// location.state = { from: "/login" }
// location.search = "?tab=profile"
return <div>当前位置: {location.pathname}</div>;
}
4. 嵌套路由
4.1 嵌套路由结构
function App() {
return (
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="dashboard" element={<Dashboard />} />
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
);
}
function Layout() {
return (
<div>
<nav>
<Link to="/">首页</Link>
<Link to="/dashboard">仪表盘</Link>
<Link to="/settings">设置</Link>
</nav>
<Outlet />
</div>
);
}
关键变化: v6 使用
<Outlet>组件渲染子路由,这是 v5 嵌套方式的重大改进。
4.2 嵌套路由参数
<Routes>
<Route path="/user" element={<UserLayout />}>
<Route path=":userId" element={<UserProfile />} />
<Route path=":userId/posts" element={<UserPosts />} />
</Route>
</Routes>
function UserProfile() {
const { userId } = useParams();
return <div>用户 {userId} 的主页</div>;
}
5. 路由守卫
5.1 保护私有路由
v6 推荐使用 Outlet 实现路由守卫:
function PrivateRoute({ isAuthenticated }) {
return isAuthenticated ? <Outlet /> : <Navigate to="/login" />;
}
function App() {
const isAuthenticated = useAuth(); // 自定义认证逻辑
return (
<Routes>
<Route path="/login" element={<Login />} />
<Route element={<PrivateRoute isAuthenticated={isAuthenticated} />}>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/profile" element={<Profile />} />
</Route>
</Routes>
);
}
5.2 条件重定向
function RedirectIfLoggedIn({ children }) {
const { isAuthenticated } = useAuth();
const location = useLocation();
if (isAuthenticated) {
return <Navigate to="/dashboard" state={{ from: location }} replace />;
}
return children;
}
6. 路由匹配与优先级
6.1 精确匹配
v6 默认使用精确匹配:
// 精确匹配 "/" - 不会匹配 "/about"
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
// 使用 * 匹配任意路径
<Route path="/products/*" element={<ProductRoutes />} />
6.2 404 页面
<Routes>
<Route path="/" element={<Home />} />
<Route path="*" element={<NotFound />} />
</Routes>
7. v5 到 v6 迁移对照表
| v5 语法 | v6 语法 |
|---|---|
<Switch> | <Routes> |
component={User} | element={<User />} |
render={() => <User />} | element={<User />} |
this.props.history.push() | useNavigate() |
this.props.match.params | useParams() |
<Redirect to="/path" /> | <Navigate to="/path" /> |
嵌套路由使用 props.children | 使用 <Outlet /> |
8. 总结
React Router v6 带来了多项重要改进:
- Hooks 优先: 推荐使用 Hooks 获取路由信息,代码更简洁
- Outlet 组件: 简化嵌套路由的实现
- Routes 升级: 自动选择最佳匹配,告别手动排序
- Navigate 组件: 统一重定向逻辑
这些改变使得路由配置更加声明式,代码更具可维护性。