这是一篇为你梳理的 React Router 核心知识文章,精简、到位、易懂,帮助你快速掌握 React 路由的用法。
前言
React Router 是 React 应用中最流行的路由库,它允许你在单页应用中实现多页面导航,保持 UI 与 URL 同步。当前主流版本是 v6,如果你还在用 v5,建议升级------v6 的 API 更简洁,思维模型也更清晰。
一、核心思想
一句话:根据 URL 的不同,渲染不同的组件。
React Router 将"路由"看作一个组件树,URL 变化时,它会匹配对应的 <Route>,然后把组件渲染到 <Outlet> 位置。
二、三个必须知道的组件
1. BrowserRouter
包裹整个应用,提供路由上下文。通常放在最外层:
jsx
import { BrowserRouter } from 'react-router-dom';
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
2. Routes 与 Route
Routes 是 v6 新增的容器,替代了 v5 的 Switch。Route 定义路径与组件的映射。
jsx
import { Routes, Route } from 'react-router-dom';
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
);
}
要点:
- 使用
element属性(不再是component)。 - 匹配规则变为"最佳匹配",不再需要
exact。
3. Link 与 NavLink
声明式导航,替代 <a> 标签,避免整页刷新。
jsx
import { Link, NavLink } from 'react-router-dom';
<Link to="/about">关于</Link>
// NavLink 可以知道当前是否激活,用于菜单高亮
<NavLink to="/about" className={({ isActive }) => isActive ? 'active' : ''}>
关于
</NavLink>
三、嵌套路由与布局
v6 的嵌套路由不需要再写一大堆 /*,直接嵌套 <Route> 即可。父组件使用 <Outlet /> 来渲染子路由。
jsx
// 定义路由
<Routes>
<Route path="/dashboard" element={<Dashboard />}>
<Route path="stats" element={<Stats />} />
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
// Dashboard 组件
function Dashboard() {
return (
<div>
<h1>控制台</h1>
<nav>...</nav>
<Outlet /> {/* 子路由的内容会显示在这里 */}
</div>
);
}
访问 /dashboard/stats 时,Dashboard 和 Stats 会一起渲染,完美实现布局复用。
四、动态路由与参数
用冒号 :id 定义动态段,在组件中通过 useParams 读取。
jsx
<Route path="/users/:userId" element={<UserProfile />} />
// UserProfile 组件内
import { useParams } from 'react-router-dom';
function UserProfile() {
const { userId } = useParams();
// 根据 userId 请求数据...
}
五、编程式导航
不能用 <Link> 的场景(例如按钮点击后跳转),使用 useNavigate。
jsx
import { useNavigate } from 'react-router-dom';
function LoginButton() {
const navigate = useNavigate();
const handleLogin = async () => {
await loginApi();
navigate('/dashboard'); // 普通跳转
// navigate(-1); // 返回上一页
};
return <button onClick={handleLogin}>登录</button>;
}
六、查询参数(Query String)
v6 没有内置的 useQuery,推荐用浏览器原生的 URLSearchParams 来处理。
jsx
import { useSearchParams } from 'react-router-dom';
function SearchPage() {
const [searchParams, setSearchParams] = useSearchParams();
const keyword = searchParams.get('q') || '';
const updateKeyword = (newKeyword) => {
setSearchParams({ q: newKeyword });
};
// ...
}
useSearchParams 的用法和 useState 类似,读写查询参数非常方便。
七、404 页面与索引路由
jsx
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />}>
<Route index element={<DashboardHome />} /> {/* 访问 /dashboard 时显示 */}
<Route path="stats" element={<Stats />} />
</Route>
<Route path="*" element={<NotFound />} /> {/* 必须放在最后 */}
</Routes>
index路由:父路径精确匹配时渲染的默认子组件。*通配路由:捕获所有未匹配的路径,常用于 404 页面。
八、保护路由(权限控制)
可以封装一个 ProtectedRoute 组件,根据登录状态决定是渲染子组件还是重定向。
jsx
function ProtectedRoute({ children }) {
const isAuthenticated = useAuth(); // 自定义 Hook,返回用户登录状态
const location = useLocation();
if (!isAuthenticated) {
// 把当前路径传给登录页,登录后可跳回
return <Navigate to="/login" state={{ from: location }} replace />;
}
return children;
}
// 用法
<Route path="/dashboard" element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
} />
九、v6 变化一览(对比 v5)
| v5 | v6 |
|---|---|
<Switch> |
<Routes> |
component={Comp} |
element={<Comp />} |
无序匹配 + exact |
自动最佳匹配 |
嵌套需写完整路径或 useRouteMatch |
直接相对路径嵌套 + <Outlet> |
useHistory |
useNavigate |
useRouteMatch |
无,用相对路径和 useParams 等替代 |
| 类组件支持 | 全面拥抱 Hooks |
十、最佳实践速记
- 路由集中定义:将所有路由放在一个配置文件中,清晰可维护。
- 懒加载组件 :结合
React.lazy()和Suspense实现代码分割。 - 始终考虑 404 :加一条
path="*"的路由。 - 导航高亮用
NavLink:比手动判断更简洁。 - 权限等逻辑抽象成 wrapper 组件:保持路由配置干净。
总结
React Router 的核心就这么简单。掌握以上内容,你就能应对 90% 的实际项目需求。当需要更高级特性(如数据加载、路由过渡动画)时,再去查阅官方文档,你会发现自己已经有扎实的底子去理解它们了。