React Router v6 核心组件
下面,我们来系统的梳理关于 React Router v6 核心组件 的基本知识点:
一、BrowserRouter - 路由容器组件
1.1 核心功能与作用
<BrowserRouter>
是 React Router 的基础容器组件,提供基于 HTML5 History API 的路由功能:
- 启用客户端路由:实现无刷新页面导航
- 管理浏览历史:支持前进/后退操作
- 提供路由上下文:为子组件提供路由信息
- 同步URL与UI:URL变化时自动更新组件树
1.2 使用方式
// 入口文件 index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<React.StrictMode><BrowserRouter><App /></BrowserRouter></React.StrictMode>
);
1.3 关键配置项
<BrowserRouterbasename="/app" // 基础路径(适用于子目录部署)window={window} // 自定义window对象(SSR时使用)
>{/* 应用内容 */}
</BrowserRouter>
1.4 实现原理
二、Routes - 路由配置中心
2.1 核心功能与作用
<Routes>
是 v6 版本引入的核心组件,取代了 v5 中的 <Switch>
:
- 智能路由匹配:自动选择最佳匹配的路由
- 嵌套路由支持:简化路由层级结构
- 相对路径处理:自动继承父路由路径
- 路由优先级管理:不再依赖顺序(但仍建议合理排序)
2.2 基本使用
import { Routes, Route } from 'react-router-dom';function App() {return (<Routes><Route path="/" element={<HomePage />} /><Route path="about" element={<AboutPage />} /><Route path="products" element={<ProductsPage />} /></Routes>);
}
2.3 嵌套路由模式
<Routes><Route path="/" element={<Layout />}>{/* 嵌套路由自动继承父路径 */}<Route index element={<Home />} /><Route path="dashboard" element={<Dashboard />} /><Route path="settings" element={<Settings />} /></Route>
</Routes>// Layout组件中定义出口
function Layout() {return (<div><Header /><main><Outlet /> {/* 子路由在此渲染 */}</main><Footer /></div>);
}
2.4 路由匹配规则
模式 | 匹配路径 | 说明 |
---|---|---|
/ | 根路径 | 精确匹配 |
about | /about | 相对路径 |
users/:id | /users/123 | 路径参数 |
posts/* | /posts/2023/react | 通配符匹配 |
docs/:section? | /docs 或 /docs/getting-started | 可选参数 |
三、Route - 路由配置单元
3.1 核心属性解析
属性 | 类型 | 说明 | 必需 |
---|---|---|---|
path | string | 路由匹配路径 | 否(index路由不需要) |
element | ReactNode | 匹配时渲染的组件 | 是 |
index | boolean | 标记为索引路由 | 否 |
caseSensitive | boolean | 是否区分大小写 | 否 |
3.2 索引路由(Index Routes)
<Route path="/teams" element={<Teams />}>{/* 当URL为/teams时渲染TeamList */}<Route index element={<TeamList />} /><Route path=":teamId" element={<TeamDetail />} />
</Route>
3.3 动态路由参数
<Route path="users/:userId" element={<UserProfile />} />// 在UserProfile组件中获取参数
import { useParams } from 'react-router-dom';function UserProfile() {const { userId } = useParams();return <div>用户ID: {userId}</div>;
}
3.4 布局路由模式
<Routes>{/* 公共布局 */}<Route element={<MainLayout />}><Route path="/" element={<Home />} /><Route path="about" element={<About />} /></Route>{/* 独立布局 */}<Route element={<AuthLayout />}><Route path="login" element={<Login />} /><Route path="register" element={<Register />} /></Route>
</Routes>
四、路由导航与编程控制
4.1 声明式导航(Link组件)
import { Link } from 'react-router-dom';function Navigation() {return (<nav><Link to="/">首页</Link><Link to="/about">关于</Link><Link to="/users/123">用户资料</Link>{/* 高级用法 */}<Link to="/dashboard"state={{ from: location.pathname }} // 传递状态replace={true} // 替换历史记录reloadDocument={false} // 是否整页刷新>控制面板</Link></nav>);
}
4.2 编程式导航(useNavigate)
import { useNavigate } from 'react-router-dom';function LoginForm() {const navigate = useNavigate();const handleSubmit = async (e) => {e.preventDefault();try {await login(credentials);// 导航到目标页面navigate('/dashboard');// 相对路径导航navigate('../success');// 带状态导航navigate('/profile', { state: { newUser: true } });// 替换历史记录navigate('/home', { replace: true });// 前进/后退navigate(-1); // 后退一页navigate(2); // 前进两页} catch (error) {console.error('登录失败', error);}};return (<form onSubmit={handleSubmit}>{/* 表单内容 */}</form>);
}
4.3 获取路由信息
import { useLocation, useSearchParams,useRouteMatch
} from 'react-router-dom';function ProductPage() {const location = useLocation();const [searchParams, setSearchParams] = useSearchParams();// 获取查询参数const category = searchParams.get('category');const sort = searchParams.get('sort');// 获取路径匹配信息(v6中较少使用)const match = useRouteMatch();// 更新查询参数const updateSort = (newSort) => {setSearchParams({ ...Object.fromEntries(searchParams), sort: newSort });};return (<div><h2>产品列表</h2><p>当前分类: {category}</p><button onClick={() => updateSort('price')}>按价格排序</button>{/* 显示完整路径信息 */}<pre>{JSON.stringify(location, null, 2)}</pre></div>);
}
五、高级路由模式
5.1 路由守卫(鉴权)
// src/components/AuthRoute.jsx
import { Navigate, useLocation } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';function AuthRoute({ children, roles = [] }) {const { user, isAuthenticated } = useAuth();const location = useLocation();if (!isAuthenticated) {// 未登录重定向到登录页,并保存来源位置return <Navigate to="/login" state={{ from: location }} replace />;}if (roles.length > 0 && !roles.some(role => user.roles.includes(role))) {// 无权限访问return <Navigate to="/unauthorized" replace />;}return children;
}// 使用
<Routepath="/admin"element={<AuthRoute roles={['admin']}><AdminDashboard /></AuthRoute>}
/>
5.2 路由懒加载
import { lazy, Suspense } from 'react';const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Contact = lazy(() => import('./pages/Contact'));function App() {return (<Suspense fallback={<div>加载中...</div>}><Routes><Route path="/" element={<Home />} /><Route path="about" element={<About />} /><Route path="contact" element={<Contact />} /></Routes></Suspense>);
}
5.3 错误边界处理
<Route path="/dashboard"element={<Dashboard />}errorElement={<ErrorBoundary />} // 组件级错误边界
><Route path="analytics"element={<Analytics />}errorElement={<AnalyticsError />} // 嵌套错误边界/>
</Route>
六、实践与项目结构
6.1 推荐项目结构
src/
├── components/
│ ├── layout/
│ │ ├── MainLayout.jsx
│ │ └── AuthLayout.jsx
│ └── ui/
│ ├── Header.jsx
│ └── Footer.jsx
├── pages/
│ ├── Home.jsx
│ ├── About.jsx
│ ├── Dashboard.jsx
│ └── ...
├── routes/
│ ├── index.js # 主路由配置
│ ├── publicRoutes.js # 公开路由
│ └── privateRoutes.js # 需要认证的路由
├── App.js
└── index.js
6.2 集中式路由配置
// src/routes/index.js
import { lazy } from 'react';
import AuthLayout from '../components/layout/AuthLayout';
import MainLayout from '../components/layout/MainLayout';
import AuthRoute from '../components/AuthRoute';const Home = lazy(() => import('../pages/Home'));
const Dashboard = lazy(() => import('../pages/Dashboard'));
const Login = lazy(() => import('../pages/Login'));const routes = [{path: '/',element: <MainLayout />,children: [{ index: true, element: <Home /> },{ path: 'dashboard',element: <AuthRoute><Dashboard /></AuthRoute>},// ...其他受保护路由]},{element: <AuthLayout />,children: [{ path: 'login', element: <Login /> },{ path: 'register', element: <Register /> },{ path: 'forgot-password', element: <ForgotPassword /> },]},{path: '*',element: <NotFoundPage />}
];export default routes;// src/App.js
import { useRoutes } from 'react-router-dom';
import routes from './routes';function App() {return useRoutes(routes);
}export default App;
七、常见问题与解决方案
7.1 路由匹配问题
问题:路由不匹配或匹配错误
解决:
// 确保使用正确的路径格式
<Route path="users/:id" /> // 匹配 /users/123// 使用通配符处理未匹配路由
<Route path="*" element={<NotFound />} />// 检查嵌套路由的Outlet位置
7.2 导航循环问题
问题:鉴权逻辑导致无限重定向
解决:
// 在AuthRoute组件中添加重定向状态检查
if (location.pathname === '/login') {return children;
}
7.3 滚动恢复问题
问题:页面切换后滚动位置不正确
解决:
// 创建自定义滚动恢复组件
function ScrollToTop() {const { pathname } = useLocation();useEffect(() => {window.scrollTo(0, 0);}, [pathname]);return null;
}// 在路由配置中使用
<Routes><Route element={<><ScrollToTop /><MainLayout /></>}>{/* ...路由配置 */}</Route>
</Routes>
7.4 查询参数处理
问题:获取和更新查询参数
解决:
const [searchParams, setSearchParams] = useSearchParams();// 获取参数
const page = searchParams.get('page');// 更新参数
const updatePage = (newPage) => {searchParams.set('page', newPage);setSearchParams(searchParams);
};// 保留现有参数添加新参数
setSearchParams({ ...Object.fromEntries(searchParams), sort: 'asc' });
八、总结
8.1 React Router v6 核心概念
组件 | 功能 | 关键特性 |
---|---|---|
BrowserRouter | 路由容器 | 提供路由上下文、历史管理 |
Routes | 路由配置中心 | 智能匹配、嵌套路由支持 |
Route | 路由单元 | 路径映射、动态参数、布局控制 |
8.2 实践总结
- 合理组织路由:采用集中式配置管理路由
- 嵌套路由优化:使用布局组件和Outlet实现UI复用
- 路由守卫实现:通过高阶组件保护敏感路由
- 懒加载提升性能:结合Suspense实现代码分割
- 错误边界处理:提供友好的错误恢复体验
8.3 核心API速查
API | 功能 | 使用场景 |
---|---|---|
useNavigate | 编程导航 | 表单提交后跳转 |
useParams | 获取路径参数 | 动态路由数据加载 |
useLocation | 获取位置信息 | 页面跟踪、路由守卫 |
useSearchParams | 操作查询参数 | 筛选、排序功能 |
Outlet | 渲染嵌套路由 | 布局组件中 |