Vue 人眼中的 React Router:从 router-view 到 Outlet,原来这么玩!

本文不仅教你“怎么用 React Router”,更从 Vue 开发者的角度 对照理解每一个概念,帮助你快速上手并真正掌握这个强大的路由库。

🧭 Vue 人学 React Router 特别有优势?

如果你长期使用 Vue,初次接触 React Router 会有一种“莫名熟悉”的感觉:嵌套路由、动态参数、编程式导航……甚至连 <router-view> 的概念也几乎一模一样。但深入之后你会发现:相似的只是 API 表层,核心思想和实现机制却大不相同。

我们将从最熟悉的几个点出发:

  • 路由配置怎么写?
  • <router-view> 对应什么?
  • this.$router.push 到底变成了什么?
  • 守卫、懒加载、滚动控制还能用吗?

让我们带着这些问题,边对照边实战。


1️⃣ 路由配置对比:对象 vs JSX

在 Vue 中,我们通常使用对象方式集中定义路由,每个路由条目由 pathcomponent 等字段组成,整体挂载到 VueRouter 实例上。

const router = new VueRouter({
  routes: [
    { path: '/', component: Home },
    { path: '/about', component: About },
  ]
})

React Router 的配置方式虽然也使用数组结构,但元素本质上是 JSX 驱动的组件化配置,强调的是 声明式组件组合 的理念。

const router = createBrowserRouter([
  { path: '/', element: <Home /> },
  { path: '/about', element: <About /> },
]);

核心差异:

对比项Vue RouterReact Router
路由定义配置对象(component)JSX 元素(element)
文件推荐router/index.jsroutes.jsx(建议抽离组件)
扩展字段支持 meta可添加任意自定义属性

Tips: 如果你习惯 Vue 的 meta 字段,也可以在 React 路由对象中添加自定义字段来实现权限、标题等扩展需求。


2️⃣ 路由出口:router-view ➜ Outlet

在 Vue 项目中,<router-view> 是几乎所有页面的“动态内容承载区”。每当路由切换,它就会自动渲染对应组件。

<template>
  <router-view />
</template>

React 中没有这样的语法糖组件,而是通过 react-router-dom 提供的 <Outlet /> 实现相同功能。

function App() {
  return <Outlet />;
}

它们作用一致:当前路由命中的子组件插槽。不同在于:

  • Vue 是自动注入组件栈中的 <router-view>
  • React 需要手动引入 <Outlet />,它更明确地体现了“组合”的思想。

React 更加强调“一切显式组合”,让你清楚每一层结构的存在。


3️⃣ 编程式导航对比:this.$router.push ➜ useNavigate

Vue 中,我们习惯通过 this.$router.push 进行路由跳转:

this.$router.push('/about')
this.$router.push({ path: '/search', query: { q: 'vue' } })

而在 React 中,我们则使用 Hook 获取跳转函数:

import { useNavigate } from 'react-router-dom';

const navigate = useNavigate()
navigate('/about')
navigate({ pathname: '/search', search: '?q=vue' })

注意几点:

  • React 的导航必须在函数组件中使用;
  • 不会自动拼接 query,你需要自己构造 search 字符串;
  • 替换跳转可用 navigate('/path', { replace: true })

推荐封装: 如果你经常处理 query,可封装一个帮助函数处理 URL 拼接,更加优雅。


4️⃣ 动态参数获取对比:$route.params ➜ useParams

在 Vue 中获取动态参数很直观:

// 路由配置
{ path: '/user/:id', component: User }

// 组件内访问
const userId = this.$route.params.id;

React 中通过 useParams()

// 路由配置
{ path: "/user/:id", element: <User /> }

// 组件内获取
import { useParams } from 'react-router-dom';

function User() {
  const { id } = useParams();  // 直接解构参数
  return <div>用户ID: {id}</div>;
}

小贴士:

  • useParams() 只负责匹配 :xxx 路径参数;
  • 如果你还需要获取 ?q=keyword 这样的查询参数,则要使用 useLocation()
  • 在大型页面中,也可以封装一个自定义 Hook 来同时提取 params 和 search,更方便复用。

举例:

const useQuery = () => {
  return new URLSearchParams(useLocation().search);
}

5️⃣ 嵌套路由写法:children 一样,但语法更严格

Vue 的嵌套路由结构如下:

{
  path: '/dashboard',
  component: Dashboard,
  children: [
    { path: 'profile', component: Profile }
  ]
}

React 的写法也相似,但对路径、嵌套结构要求更高:

{
  path: '/dashboard',
  element: <Dashboard />,
  children: [
    { path: 'profile', element: <Profile /> }
  ]
}

注意事项:

  • 子路由的 path 不能以 / 开头,否则会被识别为根路径;
  • 父组件必须包含 <Outlet /> 组件,负责渲染子路由;
  • 可以搭配 <NavLink> 实现子导航栏,并使用其 isActive 状态自动高亮选中菜单项。

6️⃣ 路由守卫怎么实现?用组件包装!

Vue Router 提供全局的 beforeEach 导航守卫机制,统一控制页面访问权限:

router.beforeEach((to, from, next) => {
  if (!isAuthed && to.meta.requiresAuth) {
    next('/login')
  } else {
    next()
  }
})

React Router 则没有全局守卫概念,而是通过组件化方式实现“局部控制”:

const PrivateRoute = ({ children }) => {
  const isAuthed = useAuth(); // 自定义 Hook 返回认证状态
  return isAuthed ? children : <Navigate to="/login" replace />;
}

使用时,直接包裹需要控制的页面即可:

{
  path: '/dashboard',
  element: (
    <PrivateRoute>
      <Dashboard />
    </PrivateRoute>
  )
}

优点在于更灵活、粒度更细。你甚至可以为每一个子页面设置不同的守卫逻辑,而不是一个统一的钩子。


7️⃣ 异步路由加载(懒加载):Vue 也有,React 更灵活

Vue 支持异步组件导入,常用于路由懒加载:

const UserProfile = () => import('./UserProfile.vue')

React 的做法稍复杂一些,需要借助 React.lazySuspense

import { lazy, Suspense } from 'react';

const UserProfile = lazy(() => import('./UserProfile'));

<Suspense fallback={<Loading />}>
  <UserProfile />
</Suspense>

重点:

  • 必须使用 <Suspense> 包裹懒加载组件,否则加载期间不会有任何提示;
  • 可以将 <Suspense> 放在路由出口的高层,统一处理所有懒加载页面;
  • 结合 React Router v6.4+ 的数据加载器(Loader)功能,还可以进一步实现 SSR 支持。

8️⃣ 滚动行为处理:Vue 内置,React 手动

Vue Router 提供了 scrollBehavior() 钩子,来控制页面切换后的滚动位置:

scrollBehavior() {
  return { x: 0, y: 0 }
}

React Router 没有内建 scrollBehavior,但提供了更灵活的实现方式。你可以利用 useEffectuseLocation 自定义 Hook,搭配 window.scrollTo() 控制滚动行为。

function ScrollToTop() {
  const { pathname } = useLocation();
  useEffect(() => {
    window.scrollTo(0, 0);
  }, [pathname]);
  return null;
}

使用方式:

<>
  <ScrollToTop />
  <RouterProvider router={router} />
</>

小贴士:

  • 可以使用 window.scrollTo({ top: 0, behavior: 'smooth' }) 实现平滑滚动;
  • 也可以针对特定路由设置不同的滚动策略,进一步个性化。

🛠 实战:基于 V6.4 的完整路由实践项目

我们来实现一个小型 React 应用,包含首页(Home)、关于页(About)、用户页(User),并且展示。

项目结构:

src/
├── main.jsx
├── router.jsx
├── App.jsx
├── pages/
│   ├── Home.jsx
│   ├── About.jsx
│   ├── Login.jsx
│   └── user/
│       ├── UserLayout.jsx
│       ├── UserList.jsx
│       └── UserDetail.jsx

1. main.jsx:挂载 RouterProvider

src\index.jsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import { RouterProvider } from 'react-router-dom';
import router from './router';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
);

2. router.jsx:集中式路由配置 + 路由守卫

import {
  createBrowserRouter,
  redirect
} from 'react-router-dom';
import App from './App';
import Home from './pages/Home';
import About from './pages/About';
import Login from './pages/Login';
import UserLayout from './pages/user/UserLayout';
import UserList from './pages/user/UserList';
import UserDetail from './pages/user/UserDetail';

// 模拟鉴权
const isAuthenticated = false;

const router = createBrowserRouter([
  {
    path: '/',
    element: <App />,
    children: [
      { index: true, element: <Home /> },
      { path: 'about', element: <About /> },
      { path: 'login', element: <Login /> },

      {
        path: 'users',
        element: <UserLayout />,
        loader: () => {
          if (!isAuthenticated) {
            throw redirect('/login');
          }
          return null;
        },
        children: [
          { index: true, element: <UserList /> },
          { path: ':id', element: <UserDetail /> },
        ],
      },

      { path: '*', element: <h2>页面未找到</h2> },
    ],
  },
]);

export default router;

3. App.jsx:导航栏 + Outlet

import { Outlet, Link } from 'react-router-dom';

export default function App() {
  return (
    <div>
      <nav>
        <Link to="/">首页</Link> |
        <Link to="/about">关于</Link> |
        <Link to="/users">用户</Link> |
        <Link to="/login">登录</Link>
      </nav>
      <hr />
      <Outlet />
    </div>
  );
}

4. pages/Home.jsx:编程式导航

import { useNavigate } from 'react-router-dom';

export default function Home() {
  const navigate = useNavigate();

  return (
    <div>
      <h2>首页</h2>
      <button onClick={() => navigate('/about')}>跳转到关于</button>
    </div>
  );
}

5. 各子文件代码

// pages/About.jsx
export default function About() {
  return <h2>关于页面</h2>;
}

// pages/Login.jsx
export default function Login() {
  return <h2>请登录后访问用户页面</h2>;
}

6. pages/user/UserLayout.jsx:嵌套父路由组件

import { Outlet, Link } from 'react-router-dom';

export default function UserLayout() {
  return (
    <div>
      <h2>👤 用户中心</h2>
      <Link to="/users">用户列表</Link>
      <Outlet />
    </div>
  );
}

7. pages/user/UserList.jsx:动态参数跳转

import { Link } from 'react-router-dom';

export default function UserList() {
  const users = [
    { id: 1, name: '张三' },
    { id: 2, name: '李四' },
  ];

  return (
    <div>
      <h3>用户列表</h3>
      <ul>
        {users.map(user => (
          <li key={user.id}>
            <Link to={`/users/${user.id}`}>{user.name}</Link>
          </li>
        ))}
      </ul>
    </div>
  );
}

8. pages/user/UserDetail.jsx:获取动态参数

import { useParams } from 'react-router-dom';

export default function UserDetail() {
  const { id } = useParams();

  return (
    <div>
      <h3>用户详情</h3>
      <p>当前用户ID{id}</p>
    </div>
  );
}

9. 小总结

这个实战项目实现了:路由集中配置、嵌套路由、编程式导航、动态参数传递以及获取、路由守卫、声明式跳转。

麻雀虽小,五脏俱全哈~

✅ 总结:React Router 学起来没你想的难!

React Router 和 Vue Router 在“看上去很像”的表象下,隐藏着完全不同的实现哲学:

  • Vue 更倾向于集中式配置与隐式结构注入
  • React Router 强调显式组合、组件优先、Hooks 驱动

从路由配置、导航跳转,到嵌套结构、懒加载、权限控制,React Router 提供了一个更灵活但也更自由的生态。如果你是 Vue 开发者,这篇文章相信能让你在理解差异的基础上,快速掌握 React Router 的使用方式和设计理念。

记住一句话:React Router 不是“更复杂”,它只是“更组合”!

如果你觉得这篇文章对你有帮助,欢迎点赞 👍、收藏 ⭐、评论 💬 让我知道你在看!
后续我也会持续输出更多 React 重学系列文章,敬请期待!❤️

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值