tanstack-router
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTanStack Router
TanStack Router
Version: @tanstack/react-router@1.x
Requires: React 18.0+, TypeScript 5.0+, Vite (recommended)
版本:@tanstack/react-router@1.x
依赖要求:React 18.0+、TypeScript 5.0+、Vite(推荐)
Quick Setup
快速设置
bash
npm install @tanstack/react-router @tanstack/react-router-devtools
npm install -D @tanstack/router-pluginbash
npm install @tanstack/react-router @tanstack/react-router-devtools
npm install -D @tanstack/router-pluginVite Plugin
Vite 插件
ts
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { tanstackRouter } from '@tanstack/router-plugin/vite'
export default defineConfig({
plugins: [tanstackRouter(), react()],
})ts
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { tanstackRouter } from '@tanstack/router-plugin/vite'
export default defineConfig({
plugins: [tanstackRouter(), react()],
})Root Route
根路由
tsx
// src/routes/__root.tsx
import { createRootRoute, Outlet } from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
export const Route = createRootRoute({
component: () => (
<>
<Outlet />
<TanStackRouterDevtools />
</>
),
})tsx
// src/routes/__root.tsx
import { createRootRoute, Outlet } from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
export const Route = createRootRoute({
component: () => (
<>
<Outlet />
<TanStackRouterDevtools />
</>
),
})Unified Devtools (Recommended with Multiple TanStack Libraries)
统一开发者工具(推荐搭配多个TanStack库使用)
If using Router + Query (or other TanStack libraries), use the unified shell instead of individual devtools components:
TanStackDevtoolsbash
npm install -D @tanstack/react-devtoolstsx
// src/routes/__root.tsx
import { createRootRoute, Outlet } from '@tanstack/react-router'
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
import { TanStackDevtools } from '@tanstack/react-devtools'
export const Route = createRootRoute({
component: () => (
<>
<Outlet />
<TanStackDevtools
config={{ position: 'bottom-right' }}
plugins={[
{ name: 'TanStack Router', render: <TanStackRouterDevtoolsPanel /> },
// Add more plugins: Query, etc.
]}
/>
</>
),
})Use variants (, ) when embedding inside .
*PanelTanStackRouterDevtoolsPanelReactQueryDevtoolsPanelTanStackDevtools如果同时使用 Router + Query(或其他TanStack库),请使用统一的 外壳,而非单独的开发者工具组件:
TanStackDevtoolsbash
npm install -D @tanstack/react-devtoolstsx
// src/routes/__root.tsx
import { createRootRoute, Outlet } from '@tanstack/react-router'
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
import { TanStackDevtools } from '@tanstack/react-devtools'
export const Route = createRootRoute({
component: () => (
<>
<Outlet />
<TanStackDevtools
config={{ position: 'bottom-right' }}
plugins={[
{ name: 'TanStack Router', render: <TanStackRouterDevtoolsPanel /> },
// 添加更多插件:Query 等
]}
/>
</>
),
})当嵌入到 中时,请使用 变体(如 、)。
TanStackDevtools*PanelTanStackRouterDevtoolsPanelReactQueryDevtoolsPanelRouter Creation & Type Registration
路由创建与类型注册
tsx
// src/router.tsx
import { createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
export const router = createRouter({ routeTree })
// Register router type for global inference
declare module '@tanstack/react-router' {
interface Register {
router: typeof router
}
}tsx
// src/router.tsx
import { createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
export const router = createRouter({ routeTree })
// 注册路由类型以实现全局类型推断
declare module '@tanstack/react-router' {
interface Register {
router: typeof router
}
}Entry Point
入口文件
tsx
// src/main.tsx
import { RouterProvider } from '@tanstack/react-router'
import { router } from './router'
function App() {
return <RouterProvider router={router} />
}tsx
// src/main.tsx
import { RouterProvider } from '@tanstack/react-router'
import { router } from './router'
function App() {
return <RouterProvider router={router} />
}File Structure
文件结构
src/routes/
├── __root.tsx # Root layout (always rendered)
├── index.tsx # "/" route
├── about.tsx # "/about" route
├── posts.tsx # "/posts" layout
├── posts.index.tsx # "/posts" index
├── posts.$postId.tsx # "/posts/:postId" dynamic route
├── _auth.tsx # Pathless layout (auth guard)
├── _auth.dashboard.tsx # "/dashboard" (wrapped by _auth)
└── (settings)/
├── settings.tsx # Route group
└── settings.profile.tsxsrc/routes/
├── __root.tsx # 根布局(始终渲染)
├── index.tsx # "/" 路由
├── about.tsx # "/about" 路由
├── posts.tsx # "/posts" 布局
├── posts.index.tsx # "/posts" 索引路由
├── posts.$postId.tsx # "/posts/:postId" 动态路由
├── _auth.tsx # 无路径布局(权限守卫)
├── _auth.dashboard.tsx # "/dashboard"(被 _auth 包裹)
└── (settings)/
├── settings.tsx # 路由分组
└── settings.profile.tsxRule Categories
规则分类
| Priority | Category | Rule File | Impact |
|---|---|---|---|
| CRITICAL | Type Safety | | Prevents runtime errors, enables refactoring |
| CRITICAL | File-Based Routing | | Ensures maintainable route structure |
| HIGH | Router Config | | Global defaults for preload, scroll, errors |
| HIGH | Data Loading | | Optimizes data fetching, prevents waterfalls |
| HIGH | Query Integration | | TanStack Query + Router wiring |
| HIGH | Search Params | | Type-safe URL state management |
| HIGH | Error Handling | | Graceful error and 404 handling |
| MEDIUM | Navigation | | Type-safe links and programmatic nav |
| MEDIUM | Code Splitting | | Reduces bundle size |
| MEDIUM | Preloading | | Improves perceived performance |
| LOW | Route Context | | Dependency injection and auth guards |
| 优先级 | 分类 | 规则文件 | 影响 |
|---|---|---|---|
| CRITICAL | 类型安全 | | 防止运行时错误,支持重构 |
| CRITICAL | 基于文件的路由 | | 确保路由结构可维护 |
| HIGH | 路由配置 | | 预加载、滚动、错误处理的全局默认设置 |
| HIGH | 数据加载 | | 优化数据获取,避免请求瀑布 |
| HIGH | Query 集成 | | TanStack Query 与 Router 的关联配置 |
| HIGH | 搜索参数 | | 类型安全的 URL 状态管理 |
| HIGH | 错误处理 | | 优雅的错误与404处理 |
| MEDIUM | 导航 | | 类型安全的链接与编程式导航 |
| MEDIUM | 代码分割 | | 减小包体积 |
| MEDIUM | 预加载 | | 提升感知性能 |
| LOW | 路由上下文 | | 依赖注入与权限守卫 |
Critical Rules
核心规则
Always Do
必须遵循
- Register router type — declare module with
@tanstack/react-routerfor global type inferenceRegister.router - Use parameter in hooks (
from,useSearch,useParams) to get exact types for the current routeuseLoaderData - Validate search params — use with any Standard Schema library (Zod, Valibot, Yup, ArkType, etc.)
validateSearch - Use file-based routing — let the plugin generate the route tree, don't maintain it manually
- Use loaders for data — fetch in , not in components (prevents waterfalls, enables preloading)
loader
- 注册路由类型 — 声明 模块的
@tanstack/react-router,实现全局类型推断Register.router - 在钩子(、
useSearch、useParams)中使用useLoaderData参数,获取当前路由的精确类型from - 验证搜索参数 — 使用 搭配任意标准 Schema 库(Zod、Valibot、Yup、ArkType 等)
validateSearch - 使用基于文件的路由 — 让插件自动生成路由树,不要手动维护
- 使用加载器获取数据 — 在 中请求数据,而非组件内(避免请求瀑布,支持预加载)
loader
Never Do
禁止操作
- Don't skip type registration — without it, all hooks return unions
unknown - Don't fetch data in useEffect — use or
loaderinsteadbeforeLoad - Don't use string paths without Link's type checking — catches errors at compile time
<Link to="/typo"> - Don't put heavy logic in components — loaders run before render and enable preloading/parallel fetching
- 不要跳过类型注册 — 否则所有钩子都会返回 联合类型
unknown - 不要在 useEffect 中请求数据 — 改用 或
loaderbeforeLoad - 不要使用未经过 Link 类型检查的字符串路径 — 会在编译阶段捕获错误
<Link to="/typo"> - 不要在组件中放置重逻辑 — 加载器在渲染前运行,支持预加载/并行请求
Key Patterns
关键模式
tsx
// Auth guard with beforeLoad + redirect
export const Route = createFileRoute('/_auth')({
beforeLoad: ({ context }) => {
if (!context.auth.user) {
throw redirect({ to: '/login', search: { redirect: location.href } })
}
},
})
// Search params with Standard Schema (no adapter needed)
import { z } from 'zod'
const searchSchema = z.object({
page: z.number().default(1),
sort: z.enum(['newest', 'oldest']).default('newest'),
})
export const Route = createFileRoute('/posts')({
validateSearch: searchSchema, // Pass schema directly
})
// Loader with ensureQueryData
export const Route = createFileRoute('/posts/$postId')({
loader: ({ context, params }) =>
context.queryClient.ensureQueryData(postQueryOptions(params.postId)),
component: PostComponent,
})
function PostComponent() {
const post = Route.useLoaderData()
return <h1>{post.title}</h1>
}
// Code-split with .lazy.tsx
// posts.tsx — keeps loader (critical path)
export const Route = createFileRoute('/posts')({
loader: () => fetchPosts(),
})
// posts.lazy.tsx — splits component (loaded after)
export const Route = createLazyFileRoute('/posts')({
component: PostsComponent,
})tsx
// 基于 beforeLoad + 重定向的权限守卫
export const Route = createFileRoute('/_auth')({
beforeLoad: ({ context }) => {
if (!context.auth.user) {
throw redirect({ to: '/login', search: { redirect: location.href } })
}
},
})
// 搭配标准 Schema 的搜索参数(无需适配器)
import { z } from 'zod'
const searchSchema = z.object({
page: z.number().default(1),
sort: z.enum(['newest', 'oldest']).default('newest'),
})
export const Route = createFileRoute('/posts')({
validateSearch: searchSchema, // 直接传入 Schema
})
// 使用 ensureQueryData 的加载器
export const Route = createFileRoute('/posts/$postId')({
loader: ({ context, params }) =>
context.queryClient.ensureQueryData(postQueryOptions(params.postId)),
component: PostComponent,
})
function PostComponent() {
const post = Route.useLoaderData()
return <h1>{post.title}</h1>
}
// 使用 .lazy.tsx 实现代码分割
// posts.tsx — 保留加载器(关键路径)
export const Route = createFileRoute('/posts')({
loader: () => fetchPosts(),
})
// posts.lazy.tsx — 分割组件(后续加载)
export const Route = createLazyFileRoute('/posts')({
component: PostsComponent,
})