Wouter logo

Wouter

极简的 React 路由库,仅 ~2KB gzipped,提供最核心的路由功能。

路由React极简轻量级

Wouter 是极简主义 React 路由库,包体积仅约 2KB,核心 API 只有三个 hooks 和几个组件,不内置数据加载和路由守卫,适合小型 SPA、嵌入式 widget 和包体积极度敏感场景。

Wouter

极简的 React 路由库,仅 ~2KB gzipped,提供最核心的路由功能。

技术简介说明

Wouter 是一个极简主义的 React 路由库,由 Alexey Taktarov(molefrog)创建。它的核心设计目标是"做最少的事"——仅提供路由匹配和导航的基本能力,包体积压缩后仅约 2KB(gzipped)。在 React Router 动辄 45KB+ 的今天,Wouter 为那些不需要复杂路由功能的应用提供了一个极其轻量的替代方案。

Wouter 的设计理念是"hooks 优先"——核心 API 只有三个 hooks:useRouteuseLocationuseRouter,加上 <Router><Route><Link><Redirect> 几个组件。它不内置数据加载、路由守卫、嵌套路由等高级功能,而是将这些留给开发者按需自行实现。这种"零魔法"的设计让开发者完全掌控路由逻辑,同时避免了不必要的抽象层。

Wouter 支持浏览器(基于 locationhistory API)、哈希路由和内存路由三种模式,底层使用正则表达式进行路径匹配。虽然功能精简,但它的路由匹配能力足以覆盖大部分基础路由场景,包括动态参数、通配符、可选参数等。

基本信息

快速上手

安装

# npm
npm install wouter
 
# pnpm
pnpm add wouter
 
# yarn
yarn add wouter

基础配置

Wouter 无需特殊配置,安装后即可使用。默认使用浏览器 History API。

import { Route, Link, Switch } from 'wouter'
 
function App() {
  return (
    <div>
      <nav>
        <Link href="/">首页</Link>
        <Link href="/about">关于</Link>
      </nav>
 
      <Switch>
        <Route path="/" component={Home} />
        <Route path="/about" component={About} />
        <Route path="/user/:name" component={User} />
        <Route component={NotFound} />
      </Switch>
    </div>
  )
}

最小示例

import { render } from 'react-dom'
import { Link, Route, Switch } from 'wouter'
 
function Home() {
  return <h1>首页</h1>
}
 
function About() {
  return <h1>关于</h1>
}
 
function User({ params }: { params: { name: string } }) {
  return <h1>你好,{params.name}!</h1>
}
 
function App() {
  return (
    <div>
      <nav>
        <Link href="/"><a>首页</a></Link>
        <Link href="/about"><a>关于</a></Link>
        <Link href="/john"><a>John</a></Link>
      </nav>
 
      <Switch>
        <Route path="/" component={Home} />
        <Route path="/about" component={About} />
        <Route path="/:name" component={User} />
      </Switch>
    </div>
  )
}
 
render(<App />, document.getElementById('root'))

使用 Hooks API:

import { useRoute, useLocation } from 'wouter'
 
function App() {
  const [location, setLocation] = useLocation()
  const [match, params] = useRoute('/user/:id')
 
  return (
    <div>
      <p>当前路径:{location}</p>
      {match ? (
        <p>用户 ID:{params?.id}</p>
      ) : (
        <p>未匹配</p>
      )}
      <button onClick={() => setLocation('/user/42')}>
        导航到用户 42
      </button>
    </div>
  )
}

核心概念与架构

极简 API 设计

Wouter 的核心 API 只有:

  • &lt;Route&gt;:路由匹配组件,支持 pathcomponentchildren
  • &lt;Switch&gt;:互斥路由匹配(只渲染第一个匹配的 Route)
  • &lt;Link&gt;:导航链接组件
  • &lt;Redirect&gt;:重定向组件
  • useRoute(path):匹配当前路径是否匹配指定模式
  • useLocation():获取/设置当前位置
  • useRouter():访问路由器实例

路径匹配

Wouter 使用正则表达式进行路径匹配,支持:

  • 动态参数:/user/:id
  • 通配符:/files/*
  • 可选参数:/file/:name?
  • 自定义匹配器:传入函数代替字符串

三种 History 模式

  • 浏览器模式(默认):基于 window.historypopstate 事件
  • 哈希模式:基于 window.location.hash,通过 hashRouter 启用
  • 内存模式:基于内存中的 location 状态,适用于测试和 SSR
import { Router } from 'wouter'
import { hashLocation, memoryLocation } from 'wouter/memory'
 
// 哈希路由
<Router hook={hashLocation}>
  <App />
</Router>
 
// 内存路由(测试用)
const [hook] = memoryLocation({ initial: '/home' })
<Router hook={hook}>
  <App />
</Router>

无状态设计

Wouter 本身不维护路由表状态,它是一个"无路由表"的路由器。每个 &lt;Route&gt; 独立匹配当前 URL,&lt;Switch&gt; 提供互斥匹配。没有嵌套路由的概念——需要嵌套布局时,直接在组件内组合即可。

核心特性

  • 极小包体积:~2KB gzipped,远小于 React Router
  • Hooks APIuseRouteuseLocationuseRouter 三个核心 hooks
  • 声明式组件&lt;Route&gt;&lt;Switch&gt;&lt;Link&gt;&lt;Redirect&gt;
  • 动态路由参数:id*:name? 等模式
  • 自定义匹配器:支持传入函数进行自定义路径匹配
  • 多种 History 模式:浏览器、哈希、内存三种模式
  • 零依赖:不依赖 historypath-to-regexp 等外部库
  • TypeScript 支持:完整的类型定义
  • React 18 兼容:支持 Concurrent Mode 和 Strict Mode
  • SSR 友好:内存路由模式支持服务端渲染
  • 嵌套布局:通过组件组合实现,无框架级限制

生态图

关键依赖

  • React ≥ 16.8:核心框架依赖(需要 Hooks 支持)
  • 无其他运行时依赖

相关插件与扩展

  • wouter-params:增强型路由参数处理
  • wouter-transition:路由切换动画(实验性)
  • 社区自定义 matcher 和 middleware

社区生态

  • 相比 React Router,Wouter 的社区生态较小
  • 主要作为轻量替代方案在特定场景使用
  • 常见于微前端、嵌入式 widget、小型 SPA
  • GitHub 上有大量基于 Wouter 的示例和模板

与其他轻量路由对比

  • Wouter vs Reach Router:Reach 已归档,Wouter 仍在维护
  • Wouter vs React Router:功能差异巨大,定位不同

适用场景

  • 小型 SPA:页面少于 10 个的简单单页应用
  • 嵌入式组件/Widget:需要在已有应用中嵌入路由功能
  • 微前端子应用:子应用需要独立路由但要求包体积最小
  • 原型/快速开发:快速搭建带路由的原型,无需复杂配置
  • React 学习项目:学习 React 路由概念的最简方案
  • 包体积敏感的场景:对加载性能有严格要求的项目
  • 测试环境:内存路由模式适合单元测试

开发与工程化

开发流程

# 在现有 React 项目中添加
npm install wouter
 
# 无需额外配置,直接使用
npm run dev

项目结构建议

src/
├── components/
│   ├── Layout.tsx          # 布局组件
│   └── Nav.tsx             # 导航组件
├── pages/
│   ├── Home.tsx            # 首页
│   ├── About.tsx           # 关于页
│   └── UserDetail.tsx      # 用户详情
├── routes.tsx              # 路由配置
├── matchers.ts             # 自定义匹配器(可选)
└── App.tsx

自定义匹配器

import { Route } from 'wouter'
import type { Matcher } from 'wouter'
 
// 自定义匹配器:忽略大小写
const caseInsensitive = (pattern: string): Matcher => {
  return (path: string) => {
    if (path.toLowerCase() === pattern.toLowerCase()) {
      return {}
    }
    return null
  }
}
 
// 使用
<Route matcher={caseInsensitive} path="/About" component={About} />

路由鉴权

// Wouter 不内置鉴权,需要自行实现
function ProtectedRoute({ path, children }: { path: string; children: React.ReactNode }) {
  const [match] = useRoute(path)
  const isAuthenticated = useAuth()
 
  if (!match) return null
  if (!isAuthenticated) return <Redirect to="/login" />
  return <>{children}</>
}
 
// 使用
<ProtectedRoute path="/dashboard">
  <Dashboard />
</ProtectedRoute>

测试

import { render, screen } from '@testing-library/react'
import { Router } from 'wouter'
import { memoryLocation } from 'wouter/memory'
 
test('renders home page', () => {
  const [hook] = memoryLocation({ initial: '/' })
  render(
    <Router hook={hook}>
      <Route path="/" component={Home} />
    </Router>
  )
  expect(screen.getByText('首页')).toBeInTheDocument()
})

性能与安全

性能特点

  • 极小包体积:~2KB 对首屏加载影响可忽略
  • 无路由表构建:不需要构建路由树,每个 Route 独立匹配
  • 高效正则匹配:路径匹配使用编译后的正则表达式
  • 最小重渲染:只有匹配的路由组件渲染

优化建议

  • 对于大量路由(50+),考虑将 useRoute 的结果缓存
  • 使用 React.memo 包裹路由组件减少不必要的重渲染
  • &lt;Switch&gt; 组件确保只有一个路由渲染
  • 将不常用的路由组件使用 React.lazy 懒加载

安全注意事项

  • XSS 防护:路由参数可能包含用户输入,渲染时注意转义
  • 路由鉴权:需要自行实现,Wouter 不提供内置守卫
  • 开放重定向&lt;Redirect&gt;to 属性需要验证
  • 敏感路由:不要在 URL 中暴露敏感信息

已知性能瓶颈

  • 大量 &lt;Route&gt; 组件(100+)时的匹配开销
  • 每次 location 变化时所有 useRoute hooks 都会执行
  • &lt;Switch&gt; 内大量路由的线性匹配
  • 缺少预加载和代码分割的内置支持

技术对比

特性WouterReact Router v7TanStack RouterReach Router
包体积~2KB~45KB~30KB~8KB
路由表
嵌套路由❌ 需组件组合✅ 原生支持✅ 原生支持✅ 原生支持
数据加载❌ 无✅ Loader/Action✅ Loader❌ 无
路由守卫❌ 需自行实现⚠️ 部分✅ beforeLoad❌ 无
代码分割❌ 需手动✅ lazy()✅ 自动✅ 支持
类型安全⚠️ 基础⚠️ 部分✅ 完整❌ 弱
SSR 支持⚠️ 内存模式✅ 完整✅ 支持⚠️ 有限
学习曲线极低中等较陡
社区规模小型极大增长中已停止
适用项目大小小型中大型中大型小型
维护状态活跃(小型)活跃活跃已归档

最佳实践

路由组织

// ✅ 推荐:将路由配置集中在一个文件
// routes.tsx
import { Route, Switch } from 'wouter'
import Home from './pages/Home'
import About from './pages/About'
import UserDetail from './pages/UserDetail'
import NotFound from './pages/NotFound'
 
export function AppRoutes() {
  return (
    <Switch>
      <Route path="/" component={Home} />
      <Route path="/about" component={About} />
      <Route path="/user/:id" component={UserDetail} />
      <Route component={NotFound} />
    </Switch>
  )
}

代码分割

// ✅ 推荐:手动实现路由级代码分割
import { lazy, Suspense } from 'react'
import { Route, Switch } from 'wouter'
 
const Home = lazy(() => import('./pages/Home'))
const About = lazy(() => import('./pages/About'))
const Dashboard = lazy(() => import('./pages/Dashboard'))
 
function AppRoutes() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Switch>
        <Route path="/" component={Home} />
        <Route path="/about" component={About} />
        <Route path="/dashboard" component={Dashboard} />
      </Switch>
    </Suspense>
  )
}

全局导航钩子

// ✅ 推荐:封装导航逻辑
import { useLocation } from 'wouter'
 
function useNavigation() {
  const [, setLocation] = useLocation()
 
  return {
    navigate: (to: string) => setLocation(to),
    goBack: () => window.history.back(),
    goForward: () => window.history.forward(),
  }
}
 
// 使用
function MyComponent() {
  const { navigate } = useNavigation()
  return <button onClick={() => navigate('/about')}>关于</button>
}

常见陷阱

  • ❌ 不要在 Wouter 中期望嵌套路由功能——需要自行通过组件组合实现
  • ❌ 不要假设 Wouter 提供数据加载——需要配合 useEffect 或其他库
  • ❌ 不要将 Wouter 用于需要复杂路由鉴权的大型应用
  • ❌ 不要忘记 &lt;Link&gt; 需要包裹 &lt;a&gt; 标签(Wouter 的 &lt;Link&gt; 不直接渲染 &lt;a&gt;

技术局限与边界

已知限制

  • 无嵌套路由:不支持框架级别的嵌套路由
  • 无数据加载:没有 loader/action 等数据获取机制
  • 无路由守卫:鉴权、重定向等需要自行实现
  • 无代码分割:不支持自动路由级代码分割
  • 无预加载:没有 Link 预加载功能
  • 社区生态小:第三方插件和教程资源有限
  • 功能有限:不适合复杂的企业级路由需求

不适用场景

  • 大型企业级应用(需要完整路由功能)
  • 需要 SSR/SSG 的复杂项目
  • 需要路由鉴权和权限控制的应用
  • 需要类型安全路由的项目
  • 需要复杂数据加载和表单处理的应用
  • 需要嵌套路由和布局路由的项目

迁移注意事项

  • Wouter → React Router:需要重构路由配置,添加数据加载和守卫逻辑
  • React Router → Wouter:删除高级路由功能,简化为组件组合模式
  • 建议:如果项目需求增长超出 Wouter 能力,应尽早迁移到 React Router 或 TanStack Router

学习资源

2026 年现状

最新版本

Wouter v3.7.x 是当前稳定版本(2025年),保持低频更新。

发展趋势

  • 维护模式:更新频率较低,以 bug 修复为主
  • 稳定 API:API 已趋于稳定,很少有大变更
  • ** niche 定位**:明确定位为轻量替代方案,不追求功能全面
  • React 19 兼容:持续跟进 React 新版本的兼容性

社区活跃度

  • GitHub Stars:~7k
  • npm 周下载量:~50万+
  • 贡献者:30+
  • 更新频率:每季度 1-2 次更新

未来路线图

  • React 新版本兼容维护
  • 可能的 TypeScript 类型改进
  • 不会有大的功能扩展(保持极简定位)
  • 社区驱动的 bug 修复和小型改进