tanstack-router
9
总安装量
9
周安装量
#31738
全站排名
安装命令
npx skills add https://github.com/fellipeutaka/leon --skill tanstack-router
Agent 安装分布
opencode
9
gemini-cli
9
claude-code
9
github-copilot
9
codex
9
kimi-cli
9
Skill 文档
TanStack Router
Version: @tanstack/react-router@1.x Requires: React 18.0+, TypeScript 5.0+, Vite (recommended)
Quick Setup
npm install @tanstack/react-router @tanstack/react-router-devtools
npm install -D @tanstack/router-plugin
Vite Plugin
// 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
// 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)
If using Router + Query (or other TanStack libraries), use the unified TanStackDevtools shell instead of individual devtools components:
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.
]}
/>
</>
),
})
Use *Panel variants (TanStackRouterDevtoolsPanel, ReactQueryDevtoolsPanel) when embedding inside TanStackDevtools.
Router Creation & Type Registration
// 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
}
}
Entry Point
// 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.tsx
Rule Categories
| Priority | Category | Rule File | Impact |
|---|---|---|---|
| CRITICAL | Type Safety | rules/ts-type-safety.md |
Prevents runtime errors, enables refactoring |
| CRITICAL | File-Based Routing | rules/org-file-based-routing.md |
Ensures maintainable route structure |
| HIGH | Router Config | rules/router-configuration.md |
Global defaults for preload, scroll, errors |
| HIGH | Data Loading | rules/load-data-loading.md |
Optimizes data fetching, prevents waterfalls |
| HIGH | Query Integration | rules/load-query-integration.md |
TanStack Query + Router wiring |
| HIGH | Search Params | rules/search-params.md |
Type-safe URL state management |
| HIGH | Error Handling | rules/err-error-handling.md |
Graceful error and 404 handling |
| MEDIUM | Navigation | rules/nav-navigation.md |
Type-safe links and programmatic nav |
| MEDIUM | Code Splitting | rules/split-code-splitting.md |
Reduces bundle size |
| MEDIUM | Preloading | rules/pre-preloading.md |
Improves perceived performance |
| LOW | Route Context | rules/ctx-route-context.md |
Dependency injection and auth guards |
Critical Rules
Always Do
- Register router type â declare module
@tanstack/react-routerwithRegister.routerfor global type inference - Use
fromparameter in hooks (useSearch,useParams,useLoaderData) to get exact types for the current route - Validate search params â use
validateSearchwith any Standard Schema library (Zod, Valibot, Yup, ArkType, etc.) - Use file-based routing â let the plugin generate the route tree, don’t maintain it manually
- Use loaders for data â fetch in
loader, not in components (prevents waterfalls, enables preloading)
Never Do
- Don’t skip type registration â without it, all hooks return
unknownunions - Don’t fetch data in useEffect â use
loaderorbeforeLoadinstead - Don’t use string paths without Link’s type checking â
<Link to="/typo">catches errors at compile time - Don’t put heavy logic in components â loaders run before render and enable preloading/parallel fetching
Key Patterns
// 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,
})