TanStack Router v1 现已稳定发布,它为 React 应用的路由管理带来了一种截然不同的方法。与传统路由器不同,TanStack Router 将路由视为一等 TypeScript 公民——为您提供从路由定义一直到链接生成的端到端类型安全。
为什么选择 TanStack Router?
在深入了解配置之前,我们先来看看 TanStack Router 创建的初衷。它主要解决以下核心问题:
- 类型安全的链接 —
<Link to="/blog/$slug" params={{ slug: 'hello' }}>实现了完整的类型约束 - 内置数据加载 — 支持 Suspense 和流式渲染的路由加载器
- 搜索参数作为状态 — 经过校验且类型安全的 URL 搜索参数
- 嵌套布局 — 利用嵌套的路由树组合复杂的用户界面
安装
pnpm add @tanstack/react-router
pnpm add -D @tanstack/router-plugin @tanstack/router-devtools
基于文件的路由配置
在您的 Vite 配置文件中添加该路由插件:
// vite.config.ts
import { tanstackRouter } from '@tanstack/router-plugin/vite'
export default defineConfig({
plugins: [
tanstackRouter({ autoCodeSplitting: true }),
react(),
],
})
创建您的第一个路由
创建 src/routes/index.tsx 文件:
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/')({
component: HomePage,
})
function HomePage() {
return <h1>Welcome to my app</h1>
}
类型安全的导航
当您在不同路由之间进行导航时,它的真正威力才会显现出来:
import { Link, useNavigate } from '@tanstack/react-router'
// 完全类型安全 —— TypeScript 会捕获无效的路由
function NavBar() {
const navigate = useNavigate()
return (
<nav>
<Link to="/" className="...">Home</Link>
<Link to="/blog/$slug" params={{ slug: 'my-post' }}>Blog</Link>
<button onClick={() => navigate({ to: '/dashboard' })}>
Dashboard
</button>
</nav>
)
}
路由加载器
TanStack Router 提供了一等公民级别的路由层数据加载支持:
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/users/$userId')({
loader: async ({ params }) => {
const user = await fetchUser(params.userId)
return { user }
},
component: UserPage,
})
function UserPage() {
const { user } = Route.useLoaderData()
return <div>{user.name}</div>
}
搜索参数
类型安全的搜索参数是 TanStack Router 最强大的特性之一:
import { createFileRoute } from '@tanstack/react-router'
import { z } from 'zod'
const searchSchema = z.object({
page: z.number().default(1),
filter: z.string().optional(),
})
export const Route = createFileRoute('/products')({
validateSearch: searchSchema,
component: ProductsPage,
})
function ProductsPage() {
const { page, filter } = Route.useSearch()
// page 的类型被推断为 number,filter 的类型为 string | undefined
return <ProductGrid page={page} filter={filter} />
}
嵌套布局
使用布局路由来构建复杂的 UI 组合:
src/routes/
__root.tsx ← 根布局(页眉、页脚)
dashboard.tsx ← 仪表盘布局(侧边栏)
dashboard/
index.tsx ← /dashboard
analytics.tsx ← /dashboard/analytics
settings.tsx ← /dashboard/settings
每个布局文件通过渲染 <Outlet /> 来显示其子节点:
// dashboard.tsx
import { createFileRoute, Outlet } from '@tanstack/react-router'
export const Route = createFileRoute('/dashboard')({
component: DashboardLayout,
})
function DashboardLayout() {
return (
<div className="flex">
<Sidebar />
<main className="flex-1">
<Outlet />
</main>
</div>
)
}
后续探索
现在您已经掌握了基本用法,接下来可以探索:
- 上下文 (Context) — 在父子路由之间共享数据
- 待处理组件 (Pending components) — 在导航期间显示加载状态
- 错误边界 (Error boundaries) — 优雅地处理路由错误
- 路由守卫 (Route guards) — 重定向未授权用户
TanStack Router 将类型安全、基于文件的约定规范与强大的数据加载能力融为一体,使其成为任何 React 应用不可多得的绝佳基础。