关于 tanstack-router
面向 React 和 TypeScript 项目的 TanStack Router 技能,提供路由配置、类型安全和数据加载实践。内容涵盖文件路由、搜索参数、查询集成及错误处理。
主要功能
- 01文件路由与路由树生成
- 02类型安全的导航与参数
- 03路由加载器和数据预加载
- 04搜索参数校验
- 05错误与 404 处理
- 06代码拆分
适用场景
- 01搭建 React 文件路由
- 02管理类型安全的 URL 状态
- 03配置路由数据加载
- 04整合 TanStack Query 与 Router
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ marcioaltoe/ skills --skill tanstack-router安装后在 Claude Code 中输入/tanstack-router确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlrules/ctx-route-context.mderr-error-handling.mdload-data-loading.mdload-query-integration.mdnav-navigation.mdorg-file-based-routing.mdpre-preloading.mdrouter-configuration.mdsearch-params.mdsplit-code-splitting.mdts-type-safety.md详细介绍
TanStack Router
版本:@tanstack/react-[email protected] 要求:React 18.0+、TypeScript 5.0+、Vite(推荐)
快速设置
npm install @tanstack/react-router @tanstack/react-router-devtools
npm install -D @tanstack/router-plugin
Vite 插件
// 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()],
})
根路由
// 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 />
</>
),
})
统一开发工具(与多个 TanStack 库搭配使用时推荐)
如果同时使用 Router 和 Query(或其他 TanStack 库),请使用统一的 TanStackDevtools 外壳,而非单独的开发工具组件:
npm install -D @tanstack/react-devtools
// 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.
]}
/>
</>
),
})
在 TanStackDevtools 中嵌入时,请使用 *Panel 变体(TanStackRouterDevtoolsPanel、ReactQueryDevtoolsPanel)。
创建路由器并注册类型
// 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
}
}
入口点
// src/main.tsx
import { RouterProvider } from '@tanstack/react-router'
import { router } from './router'
function App() {
return <RouterProvider router={router} />
}
文件结构
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.tsx
规则类别
| 优先级 | 类别 | 规则文件 | 影响 |
|---|---|---|---|
| CRITICAL | 类型安全 | rules/ts-type-safety.md | 防止运行时错误,便于重构 |
| CRITICAL | 基于文件的路由 | rules/org-file-based-routing.md | 确保路由结构易于维护 |
| HIGH | 路由器配置 | rules/router-configuration.md | 设置预加载、滚动和错误处理的全局默认值 |
| HIGH | 数据加载 | rules/load-data-loading.md | 优化数据获取,防止瀑布式请求 |
| HIGH | Query 集成 | rules/load-query-integration.md | 配置 TanStack Query 与 Router |
| HIGH | 搜索参数 | rules/search-params.md | 类型安全地管理 URL 状态 |
| HIGH | 错误处理 | rules/err-error-handling.md | 优雅地处理错误和 404 |
| MEDIUM | 导航 | rules/nav-navigation.md | 类型安全的链接和编程式导航 |
| MEDIUM | 代码拆分 | rules/split-code-splitting.md | 减小打包体积 |
| MEDIUM | 预加载 | rules/pre-preloading.md | 提升感知性能 |
| LOW | 路由上下文 | rules/ctx-route-context.md | 依赖注入和身份验证守卫 |
关键规则
始终执行
- 注册路由器类型 — 声明
@tanstack/react-router模块,并通过Register.router实现全局类型推断 - 在钩子中使用
from参数(useSearch、useParams、useLoaderData),以获取当前路由的精确类型 - 验证搜索参数 — 使用
validateSearch,并搭配任意 Standard Schema 库(Zod、Valibot、Yup、ArkType 等) - 使用基于文件的路由 — 让插件生成路由树,不要手动维护
- 使用加载器获取数据 — 在
loader中获取数据,而非在组件中(防止瀑布式请求,并支持预加载)
绝不执行
- 不要跳过类型注册 — 否则所有钩子都会返回
unknown联合类型 - 不要在 useEffect 中获取数据 — 改用
loader或beforeLoad - 不要使用未经 Link 类型检查的字符串路径 —
<Link to="/typo">可在编译时捕获错误 - 不要在组件中放入复杂逻辑 — 加载器会在渲染前运行,并支持预加载和并行获取
关键模式
// 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,
})
评论
支持 Markdown