现代 React 路由实践指南

从前的前端

在很久之前的页面上,我们点击后,浏览器会有白屏一段时间,页面的跳转是后端干的事

但是后来,前端致力于用户的体验,路由渐渐的落到了前端的身上。下面我会根据一个todos小应用来说明路由的作用

两种路由形式

在 React Router 中,HashRouterBrowserRouter 是两种常见的路由实现方式。

HashRouter

HashRouter 的 URL 会带一个 #,比如 /#/about

看起来没那么清爽,但它非常全能,不需要后端配合,兼容性极好,连老旧的 IE 浏览器都能跑

特别适合部署在 GitHub Pages 这类无法自定义服务器配置的静态托管环境。

这个 '#' 看起来会不会有点'丑'?

BroswerRouter

BrowserRouter 使用的是标准的路径形式,如 /about

和传统后端路由一致,URL 更干净、可读性更强,也更利于 SEO

但它依赖 HTML5 的 History API

IE11 及更早版本不支持(不过如今主流浏览器都已全面支持)

配合路由的懒加载能力,比如用 React.lazy + Suspense,我们可以做到访问 / 时只加载 Home 组件,访问 /about 时才加载 About 组件,其他页面代码按需加载既提升了首屏性能,又优化了用户体验

因此,在现代项目中,只要能控制服务器(或使用 Vercel、Netlify 等智能托管平台),优先选择 BrowserRouter;若环境受限或需极致兼容,再退而使用 HashRouter

懒加载

懒加载,就是用到再加载

在 React 项目里,如果不做处理,所有页面的代码(比如首页、个人中心、商品详情等)都会被打包进一个大文件,用户一打开网站就得先下载这个大包,哪怕他只看首页。

而用了 React.lazy 配合 import() 之后,每个页面会被拆成独立的小文件,只有当用户真正访问那个路由时,浏览器才去请求对应的代码。比如我的todos

js 复制代码
const Home = lazy(() => import('../pages/Home')); // 分享链接
const About = lazy(() => import('../pages/About'))// 懒加载
const UserProfile = lazy(() => import('../pages/UserProfile'))
const Product = lazy(() => import('../pages/product'));
const ProductDetail = lazy(() => import('../pages/product/ProductDetail'));
const NewProduct = lazy(() => import('../pages/product/NewProduct'));
const Login = lazy(()=>import('../pages/Login'));
const ProtectRoute = lazy(()=>import('../components/ProtectRoute'));
const Pay = lazy(()=>import('../pages/Pay'));
const NotFound = lazy(()=>import('../pages/NotFound'));
const NewPath = lazy(()=>import('../pages/NewPath'));

懒加载后,首屏加载快多了,尤其对网速慢或者用手机的用户特别友好。

配合 <Suspense> 包一层,还能在加载时显示个转圈或提示,避免白屏卡顿。

不过要注意,懒加载只支持默认导出(export default,而且一般用在路由级别最合适

太细了 比如一个页面里每个按钮、每个小组件都单独懒加载。

结果:用户打开一个页面,浏览器要发 10 个、20 个小请求去加载碎片代码,反而更慢(HTTP 请求本身有开销)。反而会发太多小请求

太粗比如把所有页面打包成两三个大块,那首屏还是得下很多用不到的代码,

失去了懒加载的意义又起不到优化效果。总的来说,这是现代 React 应用提升性能、优化体验的一个基本操作。

路由的种类

在一个React项目中,路由一般放在router文件夹目录下

下面我们用实战案例来讲解以下集中路由:

普通路由:

路径是固定的,不包含参数。

jsx 复制代码
<Route path="/" element={<Home />} /> 
<Route path="/about" element={<About />} /> 
<Route path="/login" element={<Login />} />

我们可以看到当用户访问 /about时,就显示 About 组件。

这里的路径是写死的,一一对应,最简单直接。

动态路由(Dynamic Route)

路径中包含变量参数 ,用 :参数名 表示。

jsx 复制代码
<Route path="/user/:id" element={<UserProfile />} />
<Route path=":productId" element={<ProductDetail />}/>

在我们访问/user/123时 :id的值就是123

我们可以在组件UserProfile或ProductDetail里 ,可以通过useParams()拿到参数

嵌套路由(Nested Routes) + Outlet

父路由包含子路由,共享布局,子路由内容通过 Outlet 渲染。

jsx 复制代码
<Route path="/products" element={<Product/>}>
<Route path=":productId" element={<ProductDetail />}/>
<Route path="new" element={<NewProduct />}/>
</Route>

比如说我们访问 /product 会显示Product

访问/product/123 仍然显示Product

嵌套路由的好处:复用布局(比如侧边栏、导航栏),避免重复写结构。

鉴权路由(Protected Route)

jsx 复制代码
<Route path="/pay" element={
          <ProtectRoute>
            <Pay />
          </ProtectRoute>
        }>
        </Route>

访问受保护页面(如 /pay

React 渲染

jsx 复制代码
<ProtectRoute><Pay /></ProtectRoute>

而在ProtectRoute里写了以下逻辑:

jsx 复制代码
  const isLoggedIn = localStorage.getItem('isLogin') === 'true';
  if (!isLoggedIn) {
    return <Navigate to="/login"/>
  }
  return (
    <>{children}</>
    )

ProtectRoute 立刻读取 localStorage.getItem('isLogin')

如果值是 'true' → 显示 <Pay />

如果是 null'false' → 跳转到 /login 这个逻辑实现了"未登录跳转到登录页,已登录就显示内容"的核心功能

但是我们必须知道,这个鉴权只能防止用户的误操作,安全系数并不是很高,即使前端用了更先进的方法,这个不是这篇文章要讲的了。

把用户从一个旧路径自动跳转到新路径。

jsx 复制代码
<Route path="/old-path" element={<Navigate replace to="/new-path"/>}/>
<Route path="/new-path" element={<NewPath />}/>

我们在点击 <Navigate replace to="/new-path" />

浏览器不会把旧路径 /old-path 留在历史记录中,而是直接用新路径 /new-path 替换当前记录

这意味着用户点击"返回"按钮时,不会回到 /old-path,而是跳转到更早的页面。

这种机制基于 History API 的 replaceState,常用于页面改名、登录跳转或首页重定向等场景,避免无效或冗余的历史条目,让浏览器的前进/后退行为更自然、更符合预期。

总结

我们从前端接管路由开始,页面跳转不再依赖后端刷新,而是通过 React Router 实现流畅的无刷新导航。

配合懒加载,应用按需加载页面代码,显著提升了首屏速度 ;普通路由、动态路由、嵌套路由等灵活组合,满足各种场景需求;鉴权路由拦截未登录访问,重定向路由处理路径变更

这些能力共同构建了现代 React 应用高效、友好且结构清晰的导航体验。

相关推荐
三木檾2 小时前
Cookie 原理详解:Domain / Path / SameSite 一步错,生产环境直接翻车
前端·浏览器
开始学java2 小时前
踩坑实录:把 useRef 写进 JSX 后,我终于分清它和 useState 的核心差异
前端
二DUAN帝2 小时前
像素流与UE通信
前端·javascript·css·ue5·html·ue4·html5
1024小神2 小时前
cloudflare+hono框架实现jwtToken认证,并从token中拿到认证信息
前端
jinmo_C++2 小时前
从零开始学前端 · HTML 基础篇(二):常用文本标签与排版基础
前端·html
2501_944711432 小时前
A2UI : 以动态 UI 代替 LLM 文本输出的方案
开发语言·前端·ui
lili-felicity2 小时前
React Native for Harmony 企业级折叠面板 (Accordion) 组件
react native·react.js·ui
生活在一步步变好i2 小时前
前端加载优化核心知识点详解
前端
2501_948195342 小时前
RN for OpenHarmony英雄联盟助手App实战:关于实现
javascript·react native·react.js