React Router 极简指南(v6+)

这是一篇为你梳理的 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. RoutesRoute

Routes 是 v6 新增的容器,替代了 v5 的 SwitchRoute 定义路径与组件的映射。

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

声明式导航,替代 <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 时,DashboardStats 会一起渲染,完美实现布局复用。

四、动态路由与参数

用冒号 :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

十、最佳实践速记

  1. 路由集中定义:将所有路由放在一个配置文件中,清晰可维护。
  2. 懒加载组件 :结合 React.lazy()Suspense 实现代码分割。
  3. 始终考虑 404 :加一条 path="*" 的路由。
  4. 导航高亮用 NavLink:比手动判断更简洁。
  5. 权限等逻辑抽象成 wrapper 组件:保持路由配置干净。

总结

React Router 的核心就这么简单。掌握以上内容,你就能应对 90% 的实际项目需求。当需要更高级特性(如数据加载、路由过渡动画)时,再去查阅官方文档,你会发现自己已经有扎实的底子去理解它们了。

相关推荐
子兮曰21 小时前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰1 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万1 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝1 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋1 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁1 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95271 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大1 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师1 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学1 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端