React Router DOM v6与v5版本核心差异与用法详解
React Router DOM v6的发布标志着React路由管理的一次重要演进。相较于v5版本,v6在API设计、功能实现和开发体验上都有显著变化,尤其是在函数式组件和Hooks日益普及的背景下,v6的许多改动都围绕着更简洁、更现代的开发模式展开。本文将深入对比v5与v6的核心差异,并重点介绍v6的实际应用。
React Router DOM v6的主要变更
<Switch>升级为<Routes>:<Routes>提供了更优化的路由匹配逻辑。- 路由组件渲染方式变更: 使用
elementprop 替代了 v5 中的componentprop 来渲染路由匹配到的组件。 - 相对路径自动解析: 子路由的
path属性现在可以省略父路由的路径前缀,React Router 会自动处理。 useNavigate替代useHistory: 提供了更简洁的编程式导航API。<Navigate>替代<Redirect>: 用于实现路由重定向,功能更强大。- 优化的路由嵌套与
<Outlet>:<Outlet>组件作为子路由的渲染出口,类似于Vue Router中的<router-view>。 index路由: 用于定义嵌套路由中的默认路由。- 新增
useResolvedPathHook: 用于解析URL路径。 - 新增
useSearchParamsHook: 简化了URL查询参数的读写操作。 <Link>支持相对路径语法:to属性支持.和..,便于在嵌套路由中导航。path通配符限制: 仅支持*和:,移除了如?等更复杂的通配符。- 新增
useOutletContextHook: 便于在嵌套路由之间共享状态。
React Router DOM v6 基础用法
安装
npm install --save react-router-dom@6.x
全局配置
在项目的入口文件(通常是 index.js 或 main.jsx)中,使用 BrowserRouter 或 HashRouter 包裹整个应用:
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(
<BrowserRouter>
<App />
</BrowserRouter>
);
BrowserRouter vs HashRouter:
BrowserRouter: 基于 HTML5 History API,URL 不带#。在刷新页面时,如果路由 state 参数存在,BrowserRouter能更好地维持状态,因为它依赖于浏览器历史记录。HashRouter: 基于 URL 的 hash 值(#),URL 带#。在刷新页面时,hash 值相关的路由 state 可能会丢失。
路由定义方式
1. 直接在组件中定义路由
import { NavLink, Routes, Route, Navigate } from 'react-router-dom';
import About from './components/About.jsx';
import Home from './components/Home.jsx';
import Children from "./components/Children.jsx";
function App() {
return (
<div>
<nav>
<NavLink to="/home">Home</NavLink>
<NavLink to="/about">About</NavLink>
</nav>
<div className="content">
<Routes>
<Route path="/home" element={<Home />}>
{/* 嵌套路由 */}
<Route path="children" element={<Children />} />
</Route>
<Route path="/about" element={<About />} />
{/* 根路径重定向到 /home */}
<Route path="/" element={<Navigate to="/home" replace />} />
</Routes>
</div>
</div>
);
}
export default App;
<Navigate>: 当此组件被渲染时,它会改变当前 URL,实现视图切换,常用于路由重定向和设置默认加载的页面。
2. 使用路由表
// src/routes/index.js
import { Navigate } from 'react-router-dom';
import About from '../components/About.jsx';
import Home from '../components/Home.jsx';
import Children from "../components/Children.jsx";
const routeConfig = [
// 路由重定向
{
path: '/',
element: <Navigate to="/home" replace />,
},
{
path: '/home',
element: <Home />,
children: [ // 子路由配置
{
path: "children", // 相对路径
element: <Children />,
},
],
},
{
path: '/about',
element: <About />,
},
];
export default routeConfig;
在 App.jsx 中使用 useRoutes 挂载路由表:
// App.jsx
import { NavLink, useRoutes } from 'react-router-dom';
import routeConfig from './router'; // 引入路由表
function App() {
const element = useRoutes(routeConfig); // 生成路由规则
return (
<div>
<nav>
<NavLink to="/home">Home</NavLink>
<NavLink to="/about">About</NavLink>
</nav>
<div className="content">
{element} {/* 在此渲染匹配的路由组件 */}
</div>
</div>
);
}
export default App;
嵌套路由与 <Outlet>
<Outlet> 组件用于在父路由组件中指定子路由的渲染位置。
// src/components/Home.jsx
import React from 'react';
import { NavLink, Outlet } from 'react-router-dom';
function Home() {
return (
<div>
<h2>Home Page</h2>
<nav>
<NavLink to="children">Go to Children</NavLink>
</nav>
<!-- 子路由渲染出口 -->
<Outlet />
</div>
);
}
export default Home;
路由传参
1. Path Parameters (路径参数)
注册路由: 在 path 中使用 :参数名。
// 路由配置示例
{
path: '/about/:userId',
element: <About />,
}
传递参数: 使用 <NavLink> 的 to 属性或 navigate 函数。
// 使用 NavLink
<NavLink to={`/about/${someUserId}`}>User Profile</NavLink>
接收参数: 使用 useParams Hook。
import { useParams } from 'react-router-dom';
function About() {
const { userId } = useParams(); // 获取 userId 参数
return <div>User Profile for ID: {userId}</div>;
}
2. Query Parameters (查询参数/Search参数)
注册路由: 无需特殊声明,直接匹配路径。
// 路由配置示例
{
path: '/items',
element: <Items />,
}
传递参数: 在 to 属性后附加 ?参数名=值&参数名=值。
// 使用 NavLink
const itemId = 123;
const category = 'electronics';
<NavLink to={`/items?id=${itemId}&category=${category}`}>View Item</NavLink>
接收参数: 使用 useSearchParams Hook。
import { useSearchParams } from 'react-router-dom';
function Items() {
const [searchParams, setSearchParams] = useSearchParams();
const id = searchParams.get('id');
const category = searchParams.get('category');
const updateParams = () => {
setSearchParams({ id: '456', category: 'books' }); // 更新查询参数
};
return (
<div>
Item ID: {id}, Category: {category}
<button onClick={updateParams}>Update Params</button>
</div>
);
}
3. State Parameters (状态参数)
注册路由: 无需特殊声明。
// 路由配置示例
{
path: '/details',
element: <Details />,
}
传递参数: 使用 <NavLink> 或 navigate 函数的 state 属性。
// 使用 NavLink
const dataToSend = { itemId: 789, description: 'Sample Item' };
<NavLink to="/details" state={dataToSend}>View Details</NavLink>
接收参数: 使用 useLocation Hook 访问 location.state。
import { useLocation } from 'react-router-dom';
function Details() {
const location = useLocation();
// 注意: location.state 可能为 null 或 undefined
const { itemId, description } = location.state || {};
return (
<div>
Item ID: {itemId}, Description: {description}
</div>
);
}
路由跳转
1. 使用 <NavLink>
通过 to 属性进行声明式导航。
<NavLink to="/home">Go to Home</NavLink>
2. 使用 useNavigate Hook
提供编程式导航能力。
import { useNavigate } from 'react-router-dom';
function MyComponent() {
const navigate = useNavigate();
const goToChildren = () => {
// 导航到 /home/children,并传递 state
navigate('/home/children', {
replace: false, // 是否替换当前历史记录
state: { someData: 'example' },
});
};
const goBack = () => {
navigate(-1); // 后退一步
};
const goForward = () => {
navigate(1); // 前进一步
};
return (
<div>
<button onClick={goToChildren}>Go to Children with State</button>
<button onClick={goBack}>Back</button>
<button onClick={goForward}>Forward</button>
</div>
);
}
useNavigate 返回一个函数,可以直接调用该函数进行导航。除了直接传递路径,还可以传递一个表示前进/后退步数的数字。