Files
2nd/10_Wiki/Topic_Programming/Coding/React_TanStack_Router_Patterns.md
T
Antigravity Agent 9148c358d0 docs(10_Wiki): 위키 전체 재구성 — Topic_* 폴더를 4개 카테고리로 통합 + 대규모 중복 제거
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를
Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류.

- 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로
  자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거,
  동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거.
- 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming,
  Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business,
  Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로,
  나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는
  title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백).
  원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지.
- 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서.
- 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는
  지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지.
- Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경.
- 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
2026-07-05 00:33:48 +09:00

4.9 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
react-tanstack-router-patterns TanStack Router — Type-safe / loader / search params Coding draft B conceptual 2026-05-09 2026-05-09
react
router
tanstack-router
vibe-coding
language applicable_to
TS / React
Frontend
TanStack Router
file-based routing
type-safe params
loader
search validation

TanStack Router

Type-safe React router. Search params validation, file-based routing, loader, suspense 일급. React Router 의 type-safe 버전 + Next 의 file-based.

📖 핵심 개념

  • File-based: routes/*.tsx → 자동 tree.
  • Type-safe link: <Link to="/users/$id" params={{ id: '1' }} /> 컴파일 검증.
  • Search params: zod 같은 schema.
  • Loader: 라우트 진입 전 데이터 fetch.

💻 코드 패턴

Setup

yarn add @tanstack/react-router @tanstack/router-plugin
// vite.config.ts
import { TanStackRouterVite } from '@tanstack/router-plugin/vite';
plugins: [TanStackRouterVite()];

Route 정의 (file-based)

// src/routes/__root.tsx
import { Outlet, createRootRoute } from '@tanstack/react-router';
export const Route = createRootRoute({ component: () => <Outlet /> });

// src/routes/users.$id.tsx
import { createFileRoute } from '@tanstack/react-router';
import { z } from 'zod';

export const Route = createFileRoute('/users/$id')({
  params: { parse: (p) => ({ id: z.string().uuid().parse(p.id) }) },
  validateSearch: z.object({ tab: z.enum(['profile', 'orders']).default('profile') }),
  loader: async ({ params }) => api.user.get(params.id),
  component: UserPage,
});

function UserPage() {
  const { id } = Route.useParams();          // typed
  const { tab } = Route.useSearch();         // typed
  const user = Route.useLoaderData();         // typed
  return <h1>{user.name}</h1>;
}
import { Link } from '@tanstack/react-router';

<Link to="/users/$id" params={{ id: '42' }} search={{ tab: 'orders' }}>
  Profile
</Link>

// 잘못된 path / params 컴파일 에러

Navigate (programmatic)

const navigate = Route.useNavigate();
navigate({ to: '/users/$id', params: { id: '42' } });

// 또는 search 만 update
navigate({ search: (prev) => ({ ...prev, tab: 'orders' }) });

Loader + Suspense

export const Route = createFileRoute('/posts')({
  loader: async () => api.posts.list(),
  pendingComponent: () => <Spinner />,
  errorComponent: ({ error }) => <Error error={error} />,
  component: PostsPage,
});

function PostsPage() {
  const posts = Route.useLoaderData();
  return ...
}

TanStack Query 통합 (loader 안)

import { queryOptions } from '@tanstack/react-query';

const userQuery = (id: string) => queryOptions({
  queryKey: ['user', id],
  queryFn: () => api.user.get(id),
});

export const Route = createFileRoute('/users/$id')({
  loader: ({ context, params }) => context.queryClient.ensureQueryData(userQuery(params.id)),
  component: UserPage,
});

function UserPage() {
  const { id } = Route.useParams();
  const { data } = useSuspenseQuery(userQuery(id));
  return <h1>{data.name}</h1>;
}
<Link to="/posts" search={{ q: 'react', page: 2 }}>Posts</Link>

const { q, page } = Route.useSearch();

URL: /posts?q=react&page=2.

Nested layout

// routes/_app.tsx — layout
export const Route = createFileRoute('/_app')({
  component: () => (
    <div className="app">
      <Sidebar />
      <Outlet />
    </div>
  ),
});

// routes/_app.users.tsx — _app layout 안
export const Route = createFileRoute('/_app/users')({...});

Auth (beforeLoad)

export const Route = createFileRoute('/admin')({
  beforeLoad: async ({ context }) => {
    if (!context.auth.user) throw redirect({ to: '/login' });
  },
});

Devtools

import { TanStackRouterDevtools } from '@tanstack/router-devtools';

<RouterProvider router={router} />
<TanStackRouterDevtools router={router} />

🤔 의사결정 기준

상황 추천
Type-safe critical TanStack Router
Next.js Next App Router (자체)
단순 SPA React Router 6
거대 monorepo + 강 types TanStack Router
File-based + SSR Next / Remix
빠른 prototype React Router

안티패턴

  • String path concat: type 안전 X. params object.
  • Search 검증 없음: 잘못된 URL 이 crash.
  • Loader 안에 mutation: 의도와 다름. action 으로.
  • Route 별 useParams<RouteId>() 매번 type 인자: factory 활용.
  • beforeLoad 무거운 작업: 라우트 진입 느림.
  • 404 / pendingComponent 없음: 빈 화면.

🤖 LLM 활용 힌트

  • File-based + zod search/params + loader + TQ 통합 4종.
  • Vite plugin 자동 generate.
  • Devtools 필수 (개발).

🔗 관련 문서