@kood/claude-code 0.2.5 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +13 -8
- package/package.json +1 -1
- package/templates/.claude/agents/code-reviewer.md +371 -19
- package/templates/.claude/agents/dependency-manager.md +197 -0
- package/templates/.claude/agents/deployment-validator.md +136 -0
- package/templates/.claude/agents/git-operator.md +147 -0
- package/templates/.claude/agents/implementation-executor.md +202 -0
- package/templates/.claude/agents/lint-fixer.md +155 -0
- package/templates/.claude/agents/refactor-advisor.md +339 -29
- package/templates/.claude/commands/agent-creator.md +355 -0
- package/templates/.claude/commands/docs-creator.md +404 -163
- package/templates/.claude/commands/docs-refactor.md +400 -113
- package/templates/.claude/commands/execute.md +357 -185
- package/templates/.claude/commands/git-all.md +65 -71
- package/templates/.claude/commands/git-session.md +80 -64
- package/templates/.claude/commands/git.md +68 -72
- package/templates/.claude/commands/lint-fix.md +224 -109
- package/templates/.claude/commands/lint-init.md +142 -168
- package/templates/.claude/commands/plan.md +300 -84
- package/templates/.claude/commands/prd.md +497 -214
- package/templates/.claude/commands/pre-deploy.md +242 -0
- package/templates/.claude/commands/subagent-creator.md +118 -0
- package/templates/.claude/commands/version-update.md +45 -57
- package/templates/hono/CLAUDE.md +99 -54
- package/templates/hono/docs/guides/conventions.md +352 -0
- package/templates/hono/docs/guides/env-setup.md +347 -0
- package/templates/hono/docs/guides/getting-started.md +239 -0
- package/templates/hono/docs/library/hono/error-handling.md +20 -29
- package/templates/hono/docs/library/hono/index.md +25 -52
- package/templates/hono/docs/library/hono/middleware.md +16 -75
- package/templates/hono/docs/library/hono/rpc.md +7 -35
- package/templates/hono/docs/library/hono/validation.md +25 -45
- package/templates/hono/docs/library/t3-env/index.md +374 -0
- package/templates/npx/CLAUDE.md +165 -65
- package/templates/npx/docs/library/commander/index.md +10 -73
- package/templates/npx/docs/library/fs-extra/index.md +21 -113
- package/templates/npx/docs/library/prompts/index.md +30 -176
- package/templates/npx/docs/references/patterns.md +75 -48
- package/templates/tanstack-start/CLAUDE.md +101 -77
- package/templates/tanstack-start/docs/architecture.md +427 -0
- package/templates/tanstack-start/docs/design.md +558 -0
- package/templates/tanstack-start/docs/guides/conventions.md +132 -32
- package/templates/tanstack-start/docs/guides/env-setup.md +127 -62
- package/templates/tanstack-start/docs/guides/getting-started.md +81 -20
- package/templates/tanstack-start/docs/guides/hooks.md +241 -36
- package/templates/tanstack-start/docs/guides/routes.md +213 -61
- package/templates/tanstack-start/docs/guides/services.md +260 -24
- package/templates/tanstack-start/docs/library/better-auth/index.md +469 -16
- package/templates/tanstack-start/docs/library/t3-env/index.md +307 -0
- package/templates/tanstack-start/docs/library/tanstack-query/index.md +12 -21
- package/templates/tanstack-start/docs/library/tanstack-query/invalidation.md +22 -35
- package/templates/tanstack-start/docs/library/tanstack-query/optimistic-updates.md +7 -24
- package/templates/tanstack-start/docs/library/tanstack-query/use-mutation.md +26 -39
- package/templates/tanstack-start/docs/library/tanstack-query/use-query.md +23 -26
- package/templates/tanstack-start/docs/library/tanstack-router/error-handling.md +32 -147
- package/templates/tanstack-start/docs/library/tanstack-router/hooks.md +25 -167
- package/templates/tanstack-start/docs/library/tanstack-router/index.md +39 -74
- package/templates/tanstack-start/docs/library/tanstack-router/navigation.md +46 -116
- package/templates/tanstack-start/docs/library/tanstack-router/route-context.md +35 -154
- package/templates/tanstack-start/docs/library/tanstack-router/search-params.md +32 -171
- package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +7 -15
- package/templates/tanstack-start/docs/library/tanstack-start/routing.md +16 -23
- package/templates/tanstack-start/docs/library/zod/complex-types.md +12 -31
- package/templates/tanstack-start/docs/library/zod/index.md +18 -35
- package/templates/tanstack-start/docs/library/zod/transforms.md +11 -25
- package/templates/tanstack-start/docs/library/zod/validation.md +12 -34
- package/templates/.claude/agents/debug-detective.md +0 -37
- package/templates/.claude/agents/test-writer.md +0 -41
- package/templates/.claude/commands/feedback.md +0 -199
- package/templates/.claude/commands/ts-fix.md +0 -176
- package/templates/.claude/skills/command-creator/LICENSE.txt +0 -202
- package/templates/.claude/skills/command-creator/SKILL.md +0 -245
- package/templates/.claude/skills/command-creator/scripts/init_command.py +0 -244
- package/templates/.claude/skills/command-creator/scripts/package_command.py +0 -125
- package/templates/.claude/skills/command-creator/scripts/quick_validate.py +0 -143
- package/templates/.claude/skills/frontend-design/SKILL.md +0 -310
- package/templates/.claude/skills/frontend-design/references/animation-patterns.md +0 -446
- package/templates/.claude/skills/frontend-design/references/colors-2026.md +0 -244
- package/templates/.claude/skills/frontend-design/references/typography-2026.md +0 -302
- package/templates/.claude/skills/gemini-review/SKILL.md +0 -118
- package/templates/.claude/skills/gemini-review/references/checklists.md +0 -129
- package/templates/.claude/skills/gemini-review/references/prompt-templates.md +0 -274
- package/templates/.claude/skills/skill-creator/LICENSE.txt +0 -202
- package/templates/.claude/skills/skill-creator/SKILL.md +0 -184
- package/templates/.claude/skills/skill-creator/scripts/init_skill.py +0 -303
- package/templates/.claude/skills/skill-creator/scripts/package_skill.py +0 -110
- package/templates/.claude/skills/skill-creator/scripts/quick_validate.py +0 -65
- package/templates/hono/docs/library/ai-sdk/index.md +0 -190
- package/templates/hono/docs/library/ai-sdk/openrouter.md +0 -111
- package/templates/hono/docs/library/ai-sdk/providers.md +0 -102
- package/templates/hono/docs/library/ai-sdk/streaming.md +0 -146
- package/templates/hono/docs/library/ai-sdk/structured-output.md +0 -161
- package/templates/hono/docs/library/ai-sdk/tools.md +0 -144
- package/templates/hono/docs/library/drizzle/cloudflare-d1.md +0 -247
- package/templates/hono/docs/library/drizzle/config.md +0 -167
- package/templates/hono/docs/library/drizzle/index.md +0 -259
- package/templates/hono/docs/library/hono/env-setup.md +0 -169
- package/templates/hono/docs/library/pino/index.md +0 -146
- package/templates/tanstack-start/docs/architecture/architecture.md +0 -243
- package/templates/tanstack-start/docs/deployment/cloudflare.md +0 -132
- package/templates/tanstack-start/docs/deployment/index.md +0 -163
- package/templates/tanstack-start/docs/deployment/nitro.md +0 -110
- package/templates/tanstack-start/docs/deployment/railway.md +0 -147
- package/templates/tanstack-start/docs/deployment/vercel.md +0 -135
- package/templates/tanstack-start/docs/design/components.md +0 -175
- package/templates/tanstack-start/docs/design/index.md +0 -151
- package/templates/tanstack-start/docs/design/safe-area.md +0 -118
- package/templates/tanstack-start/docs/design/tailwind-setup.md +0 -156
- package/templates/tanstack-start/docs/library/ai-sdk/hooks.md +0 -472
- package/templates/tanstack-start/docs/library/ai-sdk/index.md +0 -264
- package/templates/tanstack-start/docs/library/ai-sdk/openrouter.md +0 -371
- package/templates/tanstack-start/docs/library/ai-sdk/providers.md +0 -403
- package/templates/tanstack-start/docs/library/ai-sdk/streaming.md +0 -320
- package/templates/tanstack-start/docs/library/ai-sdk/structured-output.md +0 -454
- package/templates/tanstack-start/docs/library/ai-sdk/tools.md +0 -473
- package/templates/tanstack-start/docs/library/better-auth/2fa.md +0 -48
- package/templates/tanstack-start/docs/library/better-auth/advanced.md +0 -55
- package/templates/tanstack-start/docs/library/better-auth/plugins.md +0 -34
- package/templates/tanstack-start/docs/library/better-auth/session.md +0 -47
- package/templates/tanstack-start/docs/library/better-auth/setup.md +0 -41
- package/templates/tanstack-start/docs/library/drizzle/cloudflare-d1.md +0 -147
- package/templates/tanstack-start/docs/library/drizzle/config.md +0 -118
- package/templates/tanstack-start/docs/library/drizzle/crud.md +0 -205
- package/templates/tanstack-start/docs/library/drizzle/index.md +0 -79
- package/templates/tanstack-start/docs/library/drizzle/relations.md +0 -202
- package/templates/tanstack-start/docs/library/drizzle/schema.md +0 -154
- package/templates/tanstack-start/docs/library/drizzle/setup.md +0 -96
- package/templates/tanstack-start/docs/library/drizzle/transactions.md +0 -127
- package/templates/tanstack-start/docs/library/pino/index.md +0 -320
- /package/templates/hono/docs/{architecture/architecture.md → architecture.md} +0 -0
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
# TanStack Router - Error Handling
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## errorComponent
|
|
6
|
-
|
|
7
|
-
loader/beforeLoad에서 에러 발생 시 표시.
|
|
3
|
+
<patterns>
|
|
8
4
|
|
|
9
5
|
```tsx
|
|
10
|
-
|
|
11
|
-
import type { ErrorComponentProps } from '@tanstack/react-router'
|
|
12
|
-
|
|
6
|
+
// errorComponent
|
|
13
7
|
export const Route = createFileRoute('/posts/$postId')({
|
|
14
8
|
loader: async ({ params }) => {
|
|
15
9
|
const post = await getPost(params.postId)
|
|
@@ -20,170 +14,68 @@ export const Route = createFileRoute('/posts/$postId')({
|
|
|
20
14
|
component: PostPage,
|
|
21
15
|
})
|
|
22
16
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
)
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## notFoundComponent
|
|
35
|
-
|
|
36
|
-
`notFound()` 호출 시 표시.
|
|
37
|
-
|
|
38
|
-
```tsx
|
|
39
|
-
import { createFileRoute, notFound } from '@tanstack/react-router'
|
|
17
|
+
const PostError = ({ error, reset }: ErrorComponentProps) => (
|
|
18
|
+
<div>
|
|
19
|
+
<h2>Error loading post</h2>
|
|
20
|
+
<p>{error.message}</p>
|
|
21
|
+
<button onClick={reset}>Retry</button>
|
|
22
|
+
</div>
|
|
23
|
+
)
|
|
40
24
|
|
|
25
|
+
// notFoundComponent
|
|
41
26
|
export const Route = createFileRoute('/posts/$postId')({
|
|
42
27
|
loader: async ({ params }) => {
|
|
43
28
|
const post = await getPost(params.postId)
|
|
44
|
-
if (!post) {
|
|
45
|
-
throw notFound() // notFoundComponent 렌더링
|
|
46
|
-
}
|
|
29
|
+
if (!post) throw notFound({ data: { searchedId: params.postId } })
|
|
47
30
|
return { post }
|
|
48
31
|
},
|
|
49
|
-
notFoundComponent:
|
|
32
|
+
notFoundComponent: ({ data }) => <p>Post {data?.searchedId} not found</p>,
|
|
50
33
|
component: PostPage,
|
|
51
34
|
})
|
|
52
35
|
|
|
53
|
-
|
|
54
|
-
const { postId } = Route.useParams()
|
|
55
|
-
|
|
56
|
-
return (
|
|
57
|
-
<div>
|
|
58
|
-
<h2>Post not found</h2>
|
|
59
|
-
<p>Post with ID "{postId}" does not exist.</p>
|
|
60
|
-
</div>
|
|
61
|
-
)
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### notFound에 데이터 전달
|
|
66
|
-
|
|
67
|
-
```tsx
|
|
68
|
-
export const Route = createFileRoute('/posts/$postId')({
|
|
69
|
-
loader: async ({ params }) => {
|
|
70
|
-
const post = await getPost(params.postId)
|
|
71
|
-
if (!post) {
|
|
72
|
-
throw notFound({
|
|
73
|
-
data: { searchedId: params.postId },
|
|
74
|
-
})
|
|
75
|
-
}
|
|
76
|
-
return { post }
|
|
77
|
-
},
|
|
78
|
-
notFoundComponent: ({ data }) => {
|
|
79
|
-
// data.searchedId 접근 가능
|
|
80
|
-
return <p>Post {data?.searchedId} not found</p>
|
|
81
|
-
},
|
|
82
|
-
})
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Root 404 페이지
|
|
86
|
-
|
|
87
|
-
```tsx
|
|
88
|
-
// routes/__root.tsx
|
|
89
|
-
import { createRootRoute, Outlet } from '@tanstack/react-router'
|
|
90
|
-
|
|
36
|
+
// Root 404
|
|
91
37
|
export const Route = createRootRoute({
|
|
92
38
|
component: RootLayout,
|
|
93
|
-
notFoundComponent:
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
function GlobalNotFound() {
|
|
97
|
-
return (
|
|
39
|
+
notFoundComponent: () => (
|
|
98
40
|
<div>
|
|
99
41
|
<h1>404</h1>
|
|
100
|
-
<p>Page not found</p>
|
|
101
42
|
<Link to="/">Go Home</Link>
|
|
102
43
|
</div>
|
|
103
|
-
)
|
|
104
|
-
}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
## pendingComponent
|
|
108
|
-
|
|
109
|
-
loader 실행 중 표시.
|
|
110
|
-
|
|
111
|
-
```tsx
|
|
112
|
-
export const Route = createFileRoute('/posts')({
|
|
113
|
-
loader: async () => {
|
|
114
|
-
await new Promise(r => setTimeout(r, 1000)) // 느린 로딩
|
|
115
|
-
return { posts: await getPosts() }
|
|
116
|
-
},
|
|
117
|
-
pendingComponent: () => <div>Loading posts...</div>,
|
|
118
|
-
component: PostsPage,
|
|
44
|
+
),
|
|
119
45
|
})
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### pendingMs / pendingMinMs
|
|
123
46
|
|
|
124
|
-
|
|
47
|
+
// pendingComponent
|
|
125
48
|
export const Route = createFileRoute('/posts')({
|
|
126
49
|
loader: async () => fetchPosts(),
|
|
127
50
|
pendingComponent: () => <Spinner />,
|
|
128
|
-
pendingMs: 200, // 200ms
|
|
129
|
-
pendingMinMs: 500, // 최소 500ms
|
|
51
|
+
pendingMs: 200, // 200ms 후 표시
|
|
52
|
+
pendingMinMs: 500, // 최소 500ms 유지 (깜빡임 방지)
|
|
130
53
|
component: PostsPage,
|
|
131
54
|
})
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
## Catch-all Route
|
|
135
|
-
|
|
136
|
-
```tsx
|
|
137
|
-
// routes/$.tsx - 모든 매치되지 않는 경로
|
|
138
|
-
import { createFileRoute } from '@tanstack/react-router'
|
|
139
55
|
|
|
56
|
+
// Catch-all (routes/$.tsx)
|
|
140
57
|
export const Route = createFileRoute('/$')({
|
|
141
|
-
component:
|
|
58
|
+
component: () => {
|
|
59
|
+
const { _splat } = Route.useParams()
|
|
60
|
+
return <div>Page Not Found: /{_splat}</div>
|
|
61
|
+
},
|
|
142
62
|
})
|
|
143
63
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
// params._splat에 전체 경로
|
|
147
|
-
|
|
148
|
-
return (
|
|
149
|
-
<div>
|
|
150
|
-
<h1>Page Not Found</h1>
|
|
151
|
-
<p>Path: /{params._splat}</p>
|
|
152
|
-
</div>
|
|
153
|
-
)
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
## 에러 타입 구분
|
|
158
|
-
|
|
159
|
-
```tsx
|
|
160
|
-
function CustomError({ error, reset }: ErrorComponentProps) {
|
|
161
|
-
// 네트워크 에러
|
|
64
|
+
// 에러 타입 구분
|
|
65
|
+
const CustomError = ({ error, reset }: ErrorComponentProps) => {
|
|
162
66
|
if (error instanceof TypeError && error.message.includes('fetch')) {
|
|
163
|
-
return
|
|
164
|
-
<div>
|
|
165
|
-
<p>Network error. Check your connection.</p>
|
|
166
|
-
<button onClick={reset}>Retry</button>
|
|
167
|
-
</div>
|
|
168
|
-
)
|
|
67
|
+
return <div><p>Network error</p><button onClick={reset}>Retry</button></div>
|
|
169
68
|
}
|
|
170
|
-
|
|
171
|
-
// 인증 에러
|
|
172
69
|
if (error.message.includes('unauthorized')) {
|
|
173
70
|
return <Navigate to="/login" />
|
|
174
71
|
}
|
|
175
|
-
|
|
176
|
-
// 기본 에러
|
|
177
|
-
return (
|
|
178
|
-
<div>
|
|
179
|
-
<p>Something went wrong</p>
|
|
180
|
-
<button onClick={reset}>Retry</button>
|
|
181
|
-
</div>
|
|
182
|
-
)
|
|
72
|
+
return <div><p>Something went wrong</p><button onClick={reset}>Retry</button></div>
|
|
183
73
|
}
|
|
184
74
|
```
|
|
185
75
|
|
|
186
|
-
|
|
76
|
+
</patterns>
|
|
77
|
+
|
|
78
|
+
<priority>
|
|
187
79
|
|
|
188
80
|
| 우선순위 | 컴포넌트 | 조건 |
|
|
189
81
|
|---------|---------|------|
|
|
@@ -192,13 +84,6 @@ function CustomError({ error, reset }: ErrorComponentProps) {
|
|
|
192
84
|
| 3 | `pendingComponent` | loader 실행 중 (pendingMs 이후) |
|
|
193
85
|
| 4 | `component` | 정상 렌더링 |
|
|
194
86
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
하위 라우트에서 처리 안 된 에러는 상위로 전파.
|
|
87
|
+
에러 전파: 하위 → 상위 (errorComponent 없으면 부모로 전파)
|
|
198
88
|
|
|
199
|
-
|
|
200
|
-
__root.tsx (errorComponent: GlobalError)
|
|
201
|
-
└── posts.tsx (errorComponent: PostsError)
|
|
202
|
-
└── $postId.tsx (errorComponent 없음)
|
|
203
|
-
→ 에러 발생 시 posts.tsx의 PostsError로 전파
|
|
204
|
-
```
|
|
89
|
+
</priority>
|
|
@@ -1,188 +1,44 @@
|
|
|
1
1
|
# TanStack Router - Hooks
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Route-Scoped Hooks
|
|
6
|
-
|
|
7
|
-
라우트 컴포넌트 내에서 사용. Type-safe.
|
|
8
|
-
|
|
9
|
-
### Route.useLoaderData()
|
|
3
|
+
<patterns>
|
|
10
4
|
|
|
11
5
|
```tsx
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
function PostPage() {
|
|
21
|
-
const { post } = Route.useLoaderData()
|
|
22
|
-
// ^? { post: Post }
|
|
6
|
+
// Route-Scoped (Type-safe)
|
|
7
|
+
const PostPage = () => {
|
|
8
|
+
const { post } = Route.useLoaderData() // Loader 반환값
|
|
9
|
+
const { postId } = Route.useParams() // Path params
|
|
10
|
+
const { page, sort } = Route.useSearch() // Search params
|
|
11
|
+
const { user } = Route.useRouteContext() // Route context
|
|
23
12
|
return <h1>{post.title}</h1>
|
|
24
13
|
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### Route.useParams()
|
|
28
|
-
|
|
29
|
-
```tsx
|
|
30
|
-
export const Route = createFileRoute('/posts/$postId')({
|
|
31
|
-
component: PostPage,
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
function PostPage() {
|
|
35
|
-
const { postId } = Route.useParams()
|
|
36
|
-
// ^? string
|
|
37
|
-
return <div>Post ID: {postId}</div>
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### Route.useSearch()
|
|
42
|
-
|
|
43
|
-
```tsx
|
|
44
|
-
export const Route = createFileRoute('/products')({
|
|
45
|
-
validateSearch: z.object({
|
|
46
|
-
page: z.number().catch(1),
|
|
47
|
-
sort: z.string().catch('newest'),
|
|
48
|
-
}),
|
|
49
|
-
component: ProductsPage,
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
function ProductsPage() {
|
|
53
|
-
const { page, sort } = Route.useSearch()
|
|
54
|
-
// ^? number, string
|
|
55
|
-
return <div>Page: {page}, Sort: {sort}</div>
|
|
56
|
-
}
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### Route.useRouteContext()
|
|
60
|
-
|
|
61
|
-
```tsx
|
|
62
|
-
// _authed.tsx에서 beforeLoad로 user 전달 가정
|
|
63
|
-
export const Route = createFileRoute('/_authed/dashboard')({
|
|
64
|
-
component: DashboardPage,
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
function DashboardPage() {
|
|
68
|
-
const { user } = Route.useRouteContext()
|
|
69
|
-
return <h1>Welcome, {user.name}</h1>
|
|
70
|
-
}
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## Global Hooks
|
|
74
|
-
|
|
75
|
-
어디서든 사용 가능. 타입 안전성 직접 지정.
|
|
76
|
-
|
|
77
|
-
### useNavigate()
|
|
78
|
-
|
|
79
|
-
```tsx
|
|
80
|
-
import { useNavigate } from '@tanstack/react-router'
|
|
81
|
-
|
|
82
|
-
function Component() {
|
|
83
|
-
const navigate = useNavigate()
|
|
84
|
-
|
|
85
|
-
const handleClick = () => {
|
|
86
|
-
navigate({
|
|
87
|
-
to: '/posts/$postId',
|
|
88
|
-
params: { postId: '123' },
|
|
89
|
-
})
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
### useMatch()
|
|
95
|
-
|
|
96
|
-
특정 라우트 매치 정보 접근.
|
|
97
|
-
|
|
98
|
-
```tsx
|
|
99
|
-
import { useMatch } from '@tanstack/react-router'
|
|
100
|
-
|
|
101
|
-
function Breadcrumb() {
|
|
102
|
-
// 특정 라우트가 현재 매치되면 정보 반환
|
|
103
|
-
const postMatch = useMatch({
|
|
104
|
-
from: '/posts/$postId',
|
|
105
|
-
shouldThrow: false, // 매치 안 되면 undefined
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
if (postMatch) {
|
|
109
|
-
return <span>Post: {postMatch.params.postId}</span>
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return null
|
|
113
|
-
}
|
|
114
|
-
```
|
|
115
14
|
|
|
116
|
-
|
|
15
|
+
// Global (Manual type)
|
|
16
|
+
const navigate = useNavigate()
|
|
17
|
+
navigate({ to: '/posts/$postId', params: { postId: '123' } })
|
|
117
18
|
|
|
118
|
-
|
|
119
|
-
|
|
19
|
+
const postMatch = useMatch({ from: '/posts/$postId', shouldThrow: false })
|
|
20
|
+
if (postMatch) return <span>Post: {postMatch.params.postId}</span>
|
|
120
21
|
|
|
121
|
-
// 타입 지정 필요
|
|
122
22
|
const { postId } = useParams({ from: '/posts/$postId' })
|
|
23
|
+
const params = useParams({ strict: false }) // 모든 params
|
|
123
24
|
|
|
124
|
-
// strict: false로 모든 params
|
|
125
|
-
const params = useParams({ strict: false })
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### useSearch() (Global)
|
|
129
|
-
|
|
130
|
-
```tsx
|
|
131
|
-
import { useSearch } from '@tanstack/react-router'
|
|
132
|
-
|
|
133
|
-
// 타입 지정 필요
|
|
134
25
|
const { page } = useSearch({ from: '/products' })
|
|
26
|
+
const search = useSearch({ strict: false }) // 현재 search
|
|
135
27
|
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
### useRouterState()
|
|
141
|
-
|
|
142
|
-
라우터 전체 상태 접근.
|
|
143
|
-
|
|
144
|
-
```tsx
|
|
145
|
-
import { useRouterState } from '@tanstack/react-router'
|
|
146
|
-
|
|
147
|
-
function CurrentPath() {
|
|
148
|
-
const pathname = useRouterState({
|
|
149
|
-
select: state => state.location.pathname,
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
return <span>Current: {pathname}</span>
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// 전체 location
|
|
156
|
-
const location = useRouterState({
|
|
157
|
-
select: state => state.location,
|
|
158
|
-
})
|
|
28
|
+
const pathname = useRouterState({ select: state => state.location.pathname })
|
|
29
|
+
const isLoading = useRouterState({ select: state => state.isLoading })
|
|
159
30
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
})
|
|
31
|
+
const location = useLocation()
|
|
32
|
+
console.log(location.pathname) // '/posts/123'
|
|
33
|
+
console.log(location.search) // { page: 1 }
|
|
164
34
|
```
|
|
165
35
|
|
|
166
|
-
|
|
36
|
+
</patterns>
|
|
167
37
|
|
|
168
|
-
|
|
38
|
+
<reference>
|
|
169
39
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
function Component() {
|
|
174
|
-
const location = useLocation()
|
|
175
|
-
|
|
176
|
-
console.log(location.pathname) // '/posts/123'
|
|
177
|
-
console.log(location.search) // { page: 1 }
|
|
178
|
-
console.log(location.hash) // '#section'
|
|
179
|
-
}
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
## Hook 비교
|
|
183
|
-
|
|
184
|
-
| Hook | Scope | Type Safety | 용도 |
|
|
185
|
-
|------|-------|-------------|------|
|
|
40
|
+
| Hook | Scope | Type | 용도 |
|
|
41
|
+
|------|-------|------|------|
|
|
186
42
|
| `Route.useLoaderData()` | Route | Auto | Loader 데이터 |
|
|
187
43
|
| `Route.useParams()` | Route | Auto | Path params |
|
|
188
44
|
| `Route.useSearch()` | Route | Auto | Search params |
|
|
@@ -193,3 +49,5 @@ function Component() {
|
|
|
193
49
|
| `useNavigate()` | Global | Auto | 네비게이션 |
|
|
194
50
|
| `useRouterState()` | Global | Manual | 라우터 상태 |
|
|
195
51
|
| `useLocation()` | Global | Auto | 현재 location |
|
|
52
|
+
|
|
53
|
+
</reference>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# TanStack Router
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> 1.x | Type-safe React Router
|
|
4
4
|
|
|
5
5
|
@navigation.md
|
|
6
6
|
@search-params.md
|
|
@@ -10,26 +10,18 @@
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
<quick_reference>
|
|
14
14
|
|
|
15
15
|
```tsx
|
|
16
|
-
import { createFileRoute, Link, Outlet } from '@tanstack/react-router'
|
|
17
|
-
|
|
18
16
|
// 기본 라우트
|
|
19
|
-
export const Route = createFileRoute('/about')({
|
|
20
|
-
component: AboutPage,
|
|
21
|
-
})
|
|
17
|
+
export const Route = createFileRoute('/about')({ component: AboutPage })
|
|
22
18
|
|
|
23
19
|
// Loader + 동적 파라미터
|
|
24
20
|
export const Route = createFileRoute('/posts/$postId')({
|
|
25
|
-
loader: async ({ params }) => {
|
|
26
|
-
const post = await getPost(params.postId)
|
|
27
|
-
return { post }
|
|
28
|
-
},
|
|
21
|
+
loader: async ({ params }) => ({ post: await getPost(params.postId) }),
|
|
29
22
|
component: PostPage,
|
|
30
23
|
})
|
|
31
|
-
|
|
32
|
-
function PostPage() {
|
|
24
|
+
const PostPage = () => {
|
|
33
25
|
const { post } = Route.useLoaderData()
|
|
34
26
|
return <h1>{post.title}</h1>
|
|
35
27
|
}
|
|
@@ -42,16 +34,35 @@ export const Route = createFileRoute('/products')({
|
|
|
42
34
|
}),
|
|
43
35
|
component: ProductsPage,
|
|
44
36
|
})
|
|
45
|
-
|
|
46
|
-
function ProductsPage() {
|
|
37
|
+
const ProductsPage = () => {
|
|
47
38
|
const { page, sort } = Route.useSearch()
|
|
48
39
|
return <div>Page {page}, Sort: {sort}</div>
|
|
49
40
|
}
|
|
41
|
+
|
|
42
|
+
// Root Route
|
|
43
|
+
export const Route = createRootRoute({
|
|
44
|
+
component: RootLayout,
|
|
45
|
+
notFoundComponent: () => <div>404</div>,
|
|
46
|
+
})
|
|
47
|
+
const RootLayout = () => (
|
|
48
|
+
<div>
|
|
49
|
+
<nav>{/* ... */}</nav>
|
|
50
|
+
<main><Outlet /></main>
|
|
51
|
+
</div>
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
// Navigation
|
|
55
|
+
<Link to="/posts/$postId" params={{ postId: '123' }}>Post</Link>
|
|
56
|
+
<Link to="/products" search={{ page: 1 }}>Products</Link>
|
|
57
|
+
|
|
58
|
+
const navigate = useNavigate()
|
|
59
|
+
navigate({ to: '/posts/$postId', params: { postId: '123' } })
|
|
60
|
+
navigate({ to: '/products', search: prev => ({ ...prev, page: 2 }) })
|
|
50
61
|
```
|
|
51
62
|
|
|
52
|
-
|
|
63
|
+
</quick_reference>
|
|
53
64
|
|
|
54
|
-
|
|
65
|
+
<structure>
|
|
55
66
|
|
|
56
67
|
```
|
|
57
68
|
routes/
|
|
@@ -61,84 +72,36 @@ routes/
|
|
|
61
72
|
├── posts/
|
|
62
73
|
│ ├── index.tsx # /posts
|
|
63
74
|
│ └── $postId.tsx # /posts/:postId
|
|
64
|
-
├── _authed/ # Protected
|
|
75
|
+
├── _authed/ # Protected (pathless)
|
|
65
76
|
│ ├── dashboard.tsx # /dashboard
|
|
66
77
|
│ └── settings.tsx # /settings
|
|
67
78
|
└── $.tsx # Catch-all (404)
|
|
68
79
|
```
|
|
69
80
|
|
|
70
|
-
| 파일명
|
|
71
|
-
|
|
81
|
+
| 파일명 | 경로 |
|
|
82
|
+
|--------|------|
|
|
72
83
|
| `index.tsx` | 디렉토리 루트 |
|
|
73
84
|
| `$param.tsx` | 동적 세그먼트 |
|
|
74
85
|
| `_layout/` | Pathless layout |
|
|
75
86
|
| `$.tsx` | Catch-all |
|
|
76
87
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
## Root Route
|
|
88
|
+
</structure>
|
|
80
89
|
|
|
81
|
-
|
|
82
|
-
// routes/__root.tsx
|
|
83
|
-
import { createRootRoute, Outlet } from '@tanstack/react-router'
|
|
84
|
-
|
|
85
|
-
export const Route = createRootRoute({
|
|
86
|
-
component: RootLayout,
|
|
87
|
-
notFoundComponent: () => <div>404 Not Found</div>,
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
function RootLayout() {
|
|
91
|
-
return (
|
|
92
|
-
<div>
|
|
93
|
-
<nav>{/* navigation */}</nav>
|
|
94
|
-
<main>
|
|
95
|
-
<Outlet />
|
|
96
|
-
</main>
|
|
97
|
-
</div>
|
|
98
|
-
)
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
---
|
|
103
|
-
|
|
104
|
-
## Route Options
|
|
90
|
+
<options>
|
|
105
91
|
|
|
106
92
|
| 옵션 | 설명 |
|
|
107
93
|
|------|------|
|
|
108
94
|
| `component` | 렌더링할 컴포넌트 |
|
|
109
95
|
| `loader` | 데이터 로드 함수 |
|
|
110
|
-
| `beforeLoad` | 로드 전 실행 (인증
|
|
96
|
+
| `beforeLoad` | 로드 전 실행 (인증 등) |
|
|
111
97
|
| `validateSearch` | Search params 스키마 |
|
|
112
98
|
| `pendingComponent` | 로딩 중 표시 |
|
|
113
99
|
| `errorComponent` | 에러 발생 시 표시 |
|
|
114
100
|
| `notFoundComponent` | Not found 시 표시 |
|
|
115
101
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
## Navigation
|
|
119
|
-
|
|
120
|
-
```tsx
|
|
121
|
-
import { Link, useNavigate } from '@tanstack/react-router'
|
|
122
|
-
|
|
123
|
-
// Link
|
|
124
|
-
<Link to="/posts/$postId" params={{ postId: '123' }}>
|
|
125
|
-
Post
|
|
126
|
-
</Link>
|
|
127
|
-
|
|
128
|
-
// Search params
|
|
129
|
-
<Link to="/products" search={{ page: 1, sort: 'newest' }}>
|
|
130
|
-
Products
|
|
131
|
-
</Link>
|
|
132
|
-
|
|
133
|
-
// Programmatic
|
|
134
|
-
const navigate = useNavigate()
|
|
135
|
-
navigate({ to: '/posts/$postId', params: { postId: '123' } })
|
|
136
|
-
navigate({ to: '/products', search: prev => ({ ...prev, page: 2 }) })
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
---
|
|
102
|
+
</options>
|
|
140
103
|
|
|
141
|
-
|
|
104
|
+
<hooks>
|
|
142
105
|
|
|
143
106
|
| Hook | 용도 |
|
|
144
107
|
|------|------|
|
|
@@ -147,4 +110,6 @@ navigate({ to: '/products', search: prev => ({ ...prev, page: 2 }) })
|
|
|
147
110
|
| `Route.useSearch()` | Search params |
|
|
148
111
|
| `Route.useRouteContext()` | Route context |
|
|
149
112
|
| `useNavigate()` | 프로그래밍 네비게이션 |
|
|
150
|
-
| `useMatch({ from })` |
|
|
113
|
+
| `useMatch({ from })` | 라우트 매치 정보 |
|
|
114
|
+
|
|
115
|
+
</hooks>
|