Back to Blog
· 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内存路由,常用于测试
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.paramsuseParams()
<Redirect to="/path" /><Navigate to="/path" />
嵌套路由使用 props.children使用 <Outlet />

8. 总结

React Router v6 带来了多项重要改进:

  • Hooks 优先: 推荐使用 Hooks 获取路由信息,代码更简洁
  • Outlet 组件: 简化嵌套路由的实现
  • Routes 升级: 自动选择最佳匹配,告别手动排序
  • Navigate 组件: 统一重定向逻辑

这些改变使得路由配置更加声明式,代码更具可维护性。

相关阅读