@kood/claude-code 0.6.6 → 0.7.0
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 +7 -1
- package/package.json +1 -1
- package/templates/.claude/agents/analyst.md +5 -0
- package/templates/.claude/agents/architect.md +5 -0
- package/templates/.claude/agents/build-fixer.md +1 -0
- package/templates/.claude/agents/code-reviewer.md +1 -0
- package/templates/.claude/agents/critic.md +4 -0
- package/templates/.claude/agents/deep-executor.md +1 -0
- package/templates/.claude/agents/dependency-manager.md +2 -0
- package/templates/.claude/agents/deployment-validator.md +2 -0
- package/templates/.claude/agents/designer.md +2 -0
- package/templates/.claude/agents/document-writer.md +3 -0
- package/templates/.claude/agents/explore.md +1 -0
- package/templates/.claude/agents/git-operator.md +2 -0
- package/templates/.claude/agents/implementation-executor.md +2 -0
- package/templates/.claude/agents/ko-to-en-translator.md +3 -0
- package/templates/.claude/agents/lint-fixer.md +2 -0
- package/templates/.claude/agents/planner.md +3 -0
- package/templates/.claude/agents/pm.md +349 -0
- package/templates/.claude/agents/qa-tester.md +1 -0
- package/templates/.claude/agents/refactor-advisor.md +4 -0
- package/templates/.claude/agents/researcher.md +9 -1
- package/templates/.claude/agents/scientist.md +1 -0
- package/templates/.claude/agents/security-reviewer.md +1 -0
- package/templates/.claude/agents/tdd-guide.md +1 -0
- package/templates/.claude/agents/vision.md +1 -0
- package/templates/.claude/instructions/agent-patterns/agent-teams-usage.md +376 -0
- package/templates/.claude/instructions/sourcing/reliable-search.md +49 -2
- package/templates/.claude/scripts/agent-teams/check-availability.sh +238 -0
- package/templates/.claude/scripts/agent-teams/setup-tmux.sh +125 -0
- package/templates/.claude/skills/agent-teams-setup/SKILL.md +460 -0
- package/templates/.claude/skills/brainstorm/SKILL.md +1 -0
- package/templates/.claude/skills/bug-fix/SKILL.md +1 -0
- package/templates/.claude/skills/crawler/SKILL.md +2 -0
- package/templates/.claude/skills/docs-creator/SKILL.md +1 -0
- package/templates/.claude/skills/docs-fetch/SKILL.md +6 -4
- package/templates/.claude/skills/docs-refactor/SKILL.md +1 -0
- package/templates/.claude/skills/elon-musk/SKILL.md +1 -0
- package/templates/.claude/skills/execute/SKILL.md +1 -0
- package/templates/.claude/skills/feedback/SKILL.md +1 -0
- package/templates/.claude/skills/figma-to-code/SKILL.md +1 -0
- package/templates/.claude/skills/genius-thinking/SKILL.md +1 -0
- package/templates/.claude/skills/global-uiux-design/SKILL.md +1 -0
- package/templates/.claude/skills/korea-uiux-design/SKILL.md +1 -0
- package/templates/.claude/skills/nextjs-react-best-practices/SKILL.md +1 -0
- package/templates/.claude/skills/plan/SKILL.md +1 -0
- package/templates/.claude/skills/prd/SKILL.md +1 -0
- package/templates/.claude/skills/project-optimizer/AGENTS.md +275 -0
- package/templates/.claude/skills/project-optimizer/SKILL.md +375 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-config-centralize.md +66 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-hot-path.md +35 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-interface-segregation.md +51 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-module-boundary.md +42 -0
- package/templates/.claude/skills/project-optimizer/rules/build-cache.md +57 -0
- package/templates/.claude/skills/project-optimizer/rules/build-code-split.md +56 -0
- package/templates/.claude/skills/project-optimizer/rules/build-incremental.md +65 -0
- package/templates/.claude/skills/project-optimizer/rules/build-minify.md +61 -0
- package/templates/.claude/skills/project-optimizer/rules/build-tree-shake.md +60 -0
- package/templates/.claude/skills/project-optimizer/rules/code-complexity.md +65 -0
- package/templates/.claude/skills/project-optimizer/rules/code-dead-elimination.md +32 -0
- package/templates/.claude/skills/project-optimizer/rules/code-duplication.md +54 -0
- package/templates/.claude/skills/project-optimizer/rules/code-error-handling.md +75 -0
- package/templates/.claude/skills/project-optimizer/rules/code-naming.md +52 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-defer-await.md +54 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-parallel.md +90 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-pipeline.md +68 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-pool.md +68 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-lightweight-alt.md +37 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-peer-align.md +44 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-security-audit.md +45 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-unused-removal.md +25 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-version-pin.md +40 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-ci-speed.md +47 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-dev-server.md +35 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-lint-config.md +36 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-test-coverage.md +34 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-type-safety.md +49 -0
- package/templates/.claude/skills/project-optimizer/rules/io-batch-queries.md +67 -0
- package/templates/.claude/skills/project-optimizer/rules/io-cache-layer.md +67 -0
- package/templates/.claude/skills/project-optimizer/rules/io-connection-reuse.md +67 -0
- package/templates/.claude/skills/project-optimizer/rules/io-serialize-minimal.md +61 -0
- package/templates/.claude/skills/project-optimizer/rules/io-stream.md +75 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-bounded-cache.md +65 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-large-data.md +64 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-lazy-init.md +78 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-leak-prevention.md +79 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-pool-reuse.md +70 -0
- package/templates/.claude/skills/ralph/SKILL.md +1 -0
- package/templates/.claude/skills/refactor/SKILL.md +1 -0
- package/templates/.claude/skills/research/SKILL.md +1 -0
- package/templates/.claude/skills/sql-optimizer/SKILL.md +438 -0
- package/templates/.claude/skills/sql-optimizer/orm-patterns.md +218 -0
- package/templates/.claude/skills/startup-validator/SKILL.md +1 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/AGENTS.md +53 -14
- package/templates/.claude/skills/tanstack-start-react-best-practices/SKILL.md +94 -27
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-defer-third-party.md +42 -19
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-optimistic-updates.md +109 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-suspense-query.md +74 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-use-hook.md +81 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-react-compiler.md +81 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-beforeload-auth.md +121 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-file-conventions.md +104 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-link-navigation.md +119 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-nested-layouts.md +155 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-path-params.md +89 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-pending-component.md +110 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-preload-strategy.md +91 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-router-context.md +120 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-search-params.md +114 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-deferred-data.md +1 -1
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-error-boundaries.md +79 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-middleware.md +85 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-serialization.md +56 -21
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-streaming.md +84 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-validator.md +71 -0
- package/templates/.claude/skills/tauri-react-best-practices/AGENTS.md +527 -0
- package/templates/.claude/skills/tauri-react-best-practices/SKILL.md +571 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-barrel-imports.md +140 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-cargo-profile.md +96 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-frontend-treeshake.md +242 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-lazy-components.md +255 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-remove-unused-commands.md +160 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-ci-pipeline.md +269 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-signing.md +207 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-updater.md +226 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-async-commands.md +172 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-batch-commands.md +133 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-binary-response.md +198 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-channel-streaming.md +186 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-error-handling.md +250 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-type-safe.md +227 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-derived-state.md +231 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-functional-setstate.md +191 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-index-maps.md +276 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-lazy-state-init.md +196 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-lifecycle.md +265 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-mobile-compat.md +199 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-permission-scope.md +193 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-error-boundary.md +239 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-event-listener.md +151 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-file-src.md +155 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-invoke-hook.md +139 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-optimistic-update.md +211 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-capability-split.md +205 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-csp.md +207 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-least-privilege.md +106 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-no-wildcard.md +253 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-scope-paths.md +160 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-async-mutex.md +270 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-mutex-pattern.md +265 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-react-sync.md +375 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-single-container.md +275 -0
- package/templates/tanstack-start/docs/architecture.md +238 -167
- package/templates/tanstack-start/docs/library/tanstack-router/error-handling.md +777 -38
- package/templates/tanstack-start/docs/library/tanstack-router/hooks.md +549 -37
- package/templates/tanstack-start/docs/library/tanstack-router/index.md +895 -111
- package/templates/tanstack-start/docs/library/tanstack-router/navigation.md +641 -43
- package/templates/tanstack-start/docs/library/tanstack-router/route-context.md +889 -38
- package/templates/tanstack-start/docs/library/tanstack-router/search-params.md +891 -29
- package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +972 -36
- package/templates/tanstack-start/docs/library/tanstack-start/index.md +1525 -881
- package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +1099 -20
- package/templates/tanstack-start/docs/library/tanstack-start/routing.md +796 -30
- package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +953 -35
- package/templates/tanstack-start/docs/library/tanstack-start/setup.md +371 -15
- package/templates/tauri/CLAUDE.md +189 -0
- package/templates/tauri/docs/guides/distribution.md +261 -0
- package/templates/tauri/docs/guides/getting-started.md +302 -0
- package/templates/tauri/docs/guides/mobile.md +288 -0
- package/templates/tauri/docs/library/tauri/index.md +510 -0
|
@@ -1,15 +1,166 @@
|
|
|
1
1
|
# TanStack Router - Navigation
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> TanStack Router v1.159.4
|
|
4
|
+
|
|
5
|
+
네비게이션 가이드. Link, useNavigate, Navigate 컴포넌트, router.navigate를 다룬다.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<navigation_concepts>
|
|
10
|
+
|
|
11
|
+
## 네비게이션 기본 개념
|
|
12
|
+
|
|
13
|
+
TanStack Router의 모든 네비게이션은 **상대적**이다. 항상 **origin**(from)에서 **destination**(to)으로 이동한다.
|
|
14
|
+
|
|
15
|
+
### 핵심 인터페이스
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// ToOptions: 모든 네비게이션 API의 기반
|
|
19
|
+
type ToOptions = {
|
|
20
|
+
from?: string // 출발 라우트 (없으면 root `/`로 간주)
|
|
21
|
+
to: string // 목적지 경로 (절대/상대 모두 가능)
|
|
22
|
+
params: object | ((prev) => object) // Path params
|
|
23
|
+
search: object | ((prev) => object) // Search params
|
|
24
|
+
hash?: string | ((prev) => string) // URL hash
|
|
25
|
+
state?: object | ((prev) => object) // History state (URL에 안 보임)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// NavigateOptions: ToOptions 확장
|
|
29
|
+
type NavigateOptions = ToOptions & {
|
|
30
|
+
replace?: boolean // history.replace 사용 여부
|
|
31
|
+
resetScroll?: boolean // 스크롤 상단 리셋 (기본 true)
|
|
32
|
+
hashScrollIntoView?: boolean | ScrollIntoViewOptions // hash 대상 스크롤
|
|
33
|
+
viewTransition?: boolean | ViewTransitionOptions // View Transition API
|
|
34
|
+
ignoreBlocker?: boolean // 네비게이션 블로커 무시
|
|
35
|
+
reloadDocument?: boolean // 전체 페이지 로드 (SPA 우회)
|
|
36
|
+
href?: string // 외부 URL 지정 (to 대신)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// LinkOptions: NavigateOptions 확장 (<a> 태그 전용)
|
|
40
|
+
type LinkOptions = NavigateOptions & {
|
|
41
|
+
target?: HTMLAnchorElement['target'] // 새 탭 열기 등
|
|
42
|
+
activeOptions?: ActiveOptions // Active 조건 설정
|
|
43
|
+
preload?: false | 'intent' // 사전 로딩 전략
|
|
44
|
+
preloadDelay?: number // 사전 로딩 지연 (ms)
|
|
45
|
+
disabled?: boolean // href 없이 렌더링
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 4가지 네비게이션 API
|
|
50
|
+
|
|
51
|
+
| API | 용도 | 특징 |
|
|
52
|
+
|-----|------|------|
|
|
53
|
+
| `<Link>` | 선언적 네비게이션 | `<a>` 태그 생성, cmd/ctrl+click 지원 |
|
|
54
|
+
| `useNavigate()` | 프로그래매틱 네비게이션 | 사이드이펙트 후 네비게이션 |
|
|
55
|
+
| `<Navigate>` | 즉시 리다이렉트 | 컴포넌트 마운트 시 즉시 이동 |
|
|
56
|
+
| `router.navigate()` | 어디서든 네비게이션 | 라우터 인스턴스가 있는 곳이면 가능 |
|
|
57
|
+
|
|
58
|
+
</navigation_concepts>
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
<link_component>
|
|
63
|
+
|
|
64
|
+
## Link: 선언적 네비게이션
|
|
65
|
+
|
|
66
|
+
기본 사용법부터 고급 옵션까지 다룬다.
|
|
67
|
+
|
|
68
|
+
### 기본 예시
|
|
4
69
|
|
|
5
70
|
```tsx
|
|
6
|
-
//
|
|
71
|
+
// 정적 라우트
|
|
7
72
|
<Link to="/about">About</Link>
|
|
8
|
-
<Link to="/posts/$postId" params={{ postId: '123' }}>Post 123</Link>
|
|
9
|
-
<Link to="/products" search={{ page: 1, sort: 'newest' }}>Products</Link>
|
|
10
|
-
<Link to="/products" search={prev => ({ ...prev, page: 2 })}>Next</Link>
|
|
11
73
|
|
|
12
|
-
//
|
|
74
|
+
// 동적 파라미터 (타입 안전)
|
|
75
|
+
<Link to="/posts/$postId" params={{ postId: '123' }}>
|
|
76
|
+
Post 123
|
|
77
|
+
</Link>
|
|
78
|
+
|
|
79
|
+
// Search params (객체)
|
|
80
|
+
<Link to="/products" search={{ page: 1, sort: 'newest' }}>
|
|
81
|
+
Products
|
|
82
|
+
</Link>
|
|
83
|
+
|
|
84
|
+
// Search params (함수: 이전 값 기반)
|
|
85
|
+
<Link to="/products" search={prev => ({ ...prev, page: 2 })}>
|
|
86
|
+
Next Page
|
|
87
|
+
</Link>
|
|
88
|
+
|
|
89
|
+
// Hash + Replace
|
|
90
|
+
<Link to="/docs" hash="intro" replace>
|
|
91
|
+
Docs
|
|
92
|
+
</Link>
|
|
93
|
+
|
|
94
|
+
// History state (URL에 보이지 않는 데이터 전달)
|
|
95
|
+
<Link to="/checkout" state={{ fromCart: true }}>
|
|
96
|
+
Checkout
|
|
97
|
+
</Link>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 상대 경로 네비게이션
|
|
101
|
+
|
|
102
|
+
`from`을 지정하면 상대 경로 사용 가능. 없으면 절대 경로로 간주.
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
// "." = 현재 라우트 리로드
|
|
106
|
+
<Link to=".">현재 라우트 리로드</Link>
|
|
107
|
+
|
|
108
|
+
// ".." = 부모 라우트로 이동
|
|
109
|
+
<Link to="..">뒤로 가기</Link>
|
|
110
|
+
|
|
111
|
+
// from 지정으로 상대 경로 사용
|
|
112
|
+
<Link from="/posts/$postId" to="../categories">
|
|
113
|
+
Categories
|
|
114
|
+
</Link>
|
|
115
|
+
|
|
116
|
+
// route.fullPath 참조 (리팩토링 안전)
|
|
117
|
+
import { Route as postIdRoute } from './routes/posts.$postId'
|
|
118
|
+
<Link from={postIdRoute.fullPath} to="../categories">
|
|
119
|
+
Categories
|
|
120
|
+
</Link>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 선택적 파라미터 (Optional Parameters)
|
|
124
|
+
|
|
125
|
+
`{-$paramName}` 구문으로 선택적 파라미터 사용.
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
// 선택적 파라미터 설정
|
|
129
|
+
<Link to="/posts/{-$category}" params={{ category: 'tech' }}>
|
|
130
|
+
Tech Posts
|
|
131
|
+
</Link>
|
|
132
|
+
|
|
133
|
+
// 선택적 파라미터 제거 (undefined로 명시)
|
|
134
|
+
<Link to="/posts/{-$category}" params={{ category: undefined }}>
|
|
135
|
+
All Posts
|
|
136
|
+
</Link>
|
|
137
|
+
|
|
138
|
+
// 함수로 조건부 설정
|
|
139
|
+
<Link
|
|
140
|
+
to="/posts/{-$category}"
|
|
141
|
+
params={prev => ({
|
|
142
|
+
...prev,
|
|
143
|
+
category: someCondition ? 'tech' : undefined,
|
|
144
|
+
})}
|
|
145
|
+
>
|
|
146
|
+
Conditional Category
|
|
147
|
+
</Link>
|
|
148
|
+
|
|
149
|
+
// 필수 + 선택 혼합
|
|
150
|
+
<Link
|
|
151
|
+
to="/users/$id/{-$tab}"
|
|
152
|
+
params={{ id: '123', tab: 'settings' }}
|
|
153
|
+
>
|
|
154
|
+
User Settings
|
|
155
|
+
</Link>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Active 상태 스타일링
|
|
159
|
+
|
|
160
|
+
현재 경로와 Link가 일치할 때 스타일 적용.
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
// 기본 활성화 체크
|
|
13
164
|
<Link
|
|
14
165
|
to="/about"
|
|
15
166
|
activeProps={{ className: 'text-blue-500 font-bold' }}
|
|
@@ -17,64 +168,511 @@
|
|
|
17
168
|
>
|
|
18
169
|
About
|
|
19
170
|
</Link>
|
|
20
|
-
<Link to="/" activeOptions={{ exact: true }}>Home</Link>
|
|
21
171
|
|
|
22
|
-
//
|
|
172
|
+
// Exact match (자식 라우트 제외)
|
|
173
|
+
<Link to="/" activeOptions={{ exact: true }}>
|
|
174
|
+
Home
|
|
175
|
+
</Link>
|
|
176
|
+
|
|
177
|
+
// Search params 포함 매칭
|
|
178
|
+
<Link
|
|
179
|
+
to="/posts"
|
|
180
|
+
search={{ page: 1 }}
|
|
181
|
+
activeOptions={{ includeSearch: true }}
|
|
182
|
+
>
|
|
183
|
+
Posts Page 1
|
|
184
|
+
</Link>
|
|
185
|
+
|
|
186
|
+
// Hash 포함 매칭
|
|
187
|
+
<Link
|
|
188
|
+
to="/docs"
|
|
189
|
+
hash="section-1"
|
|
190
|
+
activeOptions={{ includeHash: true }}
|
|
191
|
+
>
|
|
192
|
+
Section 1
|
|
193
|
+
</Link>
|
|
194
|
+
|
|
195
|
+
// data-status 속성 활용 (CSS 스타일링)
|
|
196
|
+
// 활성 시 data-status="active", 비활성 시 undefined
|
|
197
|
+
<Link to="/about">About</Link>
|
|
198
|
+
|
|
199
|
+
// isActive를 children 함수로 전달
|
|
200
|
+
<Link to="/blog/post">
|
|
201
|
+
{({ isActive }) => (
|
|
202
|
+
<>
|
|
203
|
+
<span>My Blog Post</span>
|
|
204
|
+
<Icon className={isActive ? 'active' : 'inactive'} />
|
|
205
|
+
</>
|
|
206
|
+
)}
|
|
207
|
+
</Link>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### ActiveOptions 인터페이스
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
interface ActiveOptions {
|
|
214
|
+
exact?: boolean // pathname 정확 매칭 (기본 false)
|
|
215
|
+
includeHash?: boolean // hash 포함 매칭 (기본 false)
|
|
216
|
+
includeSearch?: boolean // search 포함 매칭 (기본 true)
|
|
217
|
+
explicitUndefined?: boolean // undefined 값도 매칭 조건에 포함 (기본 false)
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Preloading 전략
|
|
222
|
+
|
|
223
|
+
사전 로딩으로 네비게이션 성능 향상.
|
|
224
|
+
|
|
225
|
+
```tsx
|
|
226
|
+
// intent: 마우스 호버 또는 터치스타트 시 로드 (권장)
|
|
227
|
+
<Link to="/posts" preload="intent">
|
|
228
|
+
Posts (빠른 로드)
|
|
229
|
+
</Link>
|
|
230
|
+
|
|
231
|
+
// 지연 시간 커스터마이즈 (기본 50ms)
|
|
232
|
+
<Link to="/blog" preload="intent" preloadDelay={100}>
|
|
233
|
+
Blog
|
|
234
|
+
</Link>
|
|
235
|
+
|
|
236
|
+
// 라우터 수준에서 기본 프리로드 설정
|
|
237
|
+
const router = createRouter({
|
|
238
|
+
routeTree,
|
|
239
|
+
defaultPreload: 'intent', // 모든 Link에 intent 적용
|
|
240
|
+
defaultPreloadDelay: 100, // 기본 지연 100ms
|
|
241
|
+
})
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### 수동 프리로딩 (router.preloadRoute)
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
const Component = () => {
|
|
248
|
+
const router = useRouter()
|
|
249
|
+
|
|
250
|
+
useEffect(() => {
|
|
251
|
+
// 특정 라우트를 수동으로 프리로드
|
|
252
|
+
router.preloadRoute({
|
|
253
|
+
to: '/posts/$postId',
|
|
254
|
+
params: { postId: '1' },
|
|
255
|
+
})
|
|
256
|
+
}, [router])
|
|
257
|
+
|
|
258
|
+
return <div />
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Link Props 참조표
|
|
263
|
+
|
|
264
|
+
| Props | 타입 | 기본값 | 설명 |
|
|
265
|
+
|-------|------|--------|------|
|
|
266
|
+
| `to` | string | - | 목적지 경로 (필수) |
|
|
267
|
+
| `from` | string | - | 출발 라우트 (상대 경로 사용 시) |
|
|
268
|
+
| `params` | object \| function | - | Path 파라미터 (타입 안전) |
|
|
269
|
+
| `search` | object \| function | - | Search params (함수로 이전 값 접근) |
|
|
270
|
+
| `hash` | string \| function | - | URL hash |
|
|
271
|
+
| `state` | object \| function | - | History state (URL에 안 보임) |
|
|
272
|
+
| `replace` | boolean | false | history.replace 사용 여부 |
|
|
273
|
+
| `resetScroll` | boolean | true | 스크롤을 상단으로 리셋 |
|
|
274
|
+
| `preload` | false \| 'intent' | - | 사전 로딩 전략 |
|
|
275
|
+
| `preloadDelay` | number | 50 | 사전 로딩 지연 (ms) |
|
|
276
|
+
| `activeProps` | object \| function | - | Active 상태 시 적용할 props |
|
|
277
|
+
| `inactiveProps` | object \| function | - | Inactive 상태 시 적용할 props |
|
|
278
|
+
| `activeOptions` | ActiveOptions | - | Active 조건 설정 |
|
|
279
|
+
| `disabled` | boolean | false | href 없이 렌더링 |
|
|
280
|
+
| `target` | string | - | 새 탭 등 표준 anchor target |
|
|
281
|
+
| `viewTransition` | boolean \| ViewTransitionOptions | - | View Transition API |
|
|
282
|
+
| `hashScrollIntoView` | boolean \| ScrollIntoViewOptions | - | hash 위치로 스크롤 |
|
|
283
|
+
|
|
284
|
+
</link_component>
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
<use_navigate>
|
|
289
|
+
|
|
290
|
+
## useNavigate: 프로그래매틱 네비게이션
|
|
291
|
+
|
|
292
|
+
이벤트 핸들러나 조건부 로직에서 네비게이션 수행. Link를 쓸 수 없는 사이드이펙트 상황에 사용.
|
|
293
|
+
|
|
294
|
+
### 기본 사용법
|
|
295
|
+
|
|
296
|
+
```tsx
|
|
23
297
|
const Component = () => {
|
|
24
298
|
const navigate = useNavigate()
|
|
25
299
|
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
300
|
+
// 정적 네비게이션
|
|
301
|
+
const handleNavigate = () => navigate({ to: '/about' })
|
|
302
|
+
|
|
303
|
+
// 동적 파라미터
|
|
304
|
+
const goToPost = (id: string) => {
|
|
305
|
+
navigate({ to: '/posts/$postId', params: { postId: id } })
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Search params 업데이트 (함수)
|
|
309
|
+
const nextPage = () => {
|
|
310
|
+
navigate({
|
|
311
|
+
to: '/products',
|
|
312
|
+
search: prev => ({ ...prev, page: (prev.page ?? 1) + 1 }),
|
|
313
|
+
})
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// History replace
|
|
317
|
+
const redirect = () => {
|
|
318
|
+
navigate({ to: '/login', replace: true })
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// 상대 경로
|
|
30
322
|
const goUp = () => navigate({ to: '..' })
|
|
31
323
|
|
|
32
|
-
return
|
|
324
|
+
return (
|
|
325
|
+
<div>
|
|
326
|
+
<button onClick={handleNavigate}>Go to About</button>
|
|
327
|
+
<button onClick={() => goToPost('123')}>View Post</button>
|
|
328
|
+
<button onClick={nextPage}>Next</button>
|
|
329
|
+
</div>
|
|
330
|
+
)
|
|
33
331
|
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### startTransition과 함께 사용
|
|
34
335
|
|
|
35
|
-
|
|
36
|
-
<Link to="/posts" preload="intent">Posts</Link> // hover 시
|
|
37
|
-
<Link to="/dashboard" preload="render">Dash</Link> // 렌더링 시
|
|
38
|
-
<Link to="/products" preload="viewport">Prod</Link> // viewport 진입 시
|
|
336
|
+
비동기 작업 완료 후 네비게이션. 폼 제출, API 호출 등에 활용.
|
|
39
337
|
|
|
40
|
-
|
|
338
|
+
```tsx
|
|
41
339
|
const SubmitButton = () => {
|
|
42
340
|
const navigate = useNavigate()
|
|
43
341
|
const [isPending, startTransition] = useTransition()
|
|
44
342
|
|
|
45
|
-
const handleSubmit = async () => {
|
|
46
|
-
|
|
343
|
+
const handleSubmit = async (formData: FormData) => {
|
|
344
|
+
// 비동기 작업 (폼 제출, 데이터 저장 등)
|
|
345
|
+
const result = await submitForm(formData)
|
|
346
|
+
|
|
47
347
|
if (result.success) {
|
|
48
|
-
startTransition
|
|
348
|
+
// startTransition으로 감싸서 네비게이션
|
|
349
|
+
startTransition(() => {
|
|
350
|
+
navigate({ to: '/success', search: { id: result.id } })
|
|
351
|
+
})
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return (
|
|
356
|
+
<button onClick={() => handleSubmit(new FormData())} disabled={isPending}>
|
|
357
|
+
{isPending ? 'Saving...' : 'Submit'}
|
|
358
|
+
</button>
|
|
359
|
+
)
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### 타입 안전 네비게이션 (from 파라미터)
|
|
364
|
+
|
|
365
|
+
현재 라우트를 명시해 타입 체크 활성화.
|
|
366
|
+
|
|
367
|
+
```tsx
|
|
368
|
+
// 타입 안전: `/posts/$postId`에서만 호출 가능
|
|
369
|
+
const navigate = useNavigate({ from: '/posts/$postId' })
|
|
370
|
+
|
|
371
|
+
const goToRelated = (relatedId: string) => {
|
|
372
|
+
navigate({
|
|
373
|
+
to: '/posts/$postId',
|
|
374
|
+
params: { postId: relatedId }, // 타입 체크됨
|
|
375
|
+
})
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Route.useNavigate()도 동일 (from 자동 지정)
|
|
379
|
+
const navigate = Route.useNavigate()
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### navigate() 옵션 참조표
|
|
383
|
+
|
|
384
|
+
| 옵션 | 타입 | 기본값 | 설명 |
|
|
385
|
+
|------|------|--------|------|
|
|
386
|
+
| `to` | string | - | 목적지 경로 (필수) |
|
|
387
|
+
| `from` | string | - | 출발 라우트 |
|
|
388
|
+
| `params` | object \| function | - | Path 파라미터 |
|
|
389
|
+
| `search` | object \| function | - | Search params |
|
|
390
|
+
| `hash` | string \| function | - | URL hash |
|
|
391
|
+
| `state` | object \| function | - | History state |
|
|
392
|
+
| `replace` | boolean | false | history.replace 사용 여부 |
|
|
393
|
+
| `resetScroll` | boolean | true | 스크롤을 상단으로 리셋 |
|
|
394
|
+
| `viewTransition` | boolean \| ViewTransitionOptions | - | View Transition API |
|
|
395
|
+
| `ignoreBlocker` | boolean | false | 네비게이션 블로커 무시 |
|
|
396
|
+
|
|
397
|
+
</use_navigate>
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
<navigate_component>
|
|
402
|
+
|
|
403
|
+
## Navigate 컴포넌트: 즉시 리다이렉트
|
|
404
|
+
|
|
405
|
+
컴포넌트 마운트 시 즉시 네비게이션. 클라이언트 전용 리다이렉트에 사용.
|
|
406
|
+
|
|
407
|
+
```tsx
|
|
408
|
+
import { Navigate } from '@tanstack/react-router'
|
|
409
|
+
|
|
410
|
+
// useNavigate + useEffect 대신 사용
|
|
411
|
+
const Component = () => {
|
|
412
|
+
return <Navigate to="/posts/$postId" params={{ postId: 'my-first-post' }} />
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// 조건부 리다이렉트
|
|
416
|
+
const ProtectedPage = () => {
|
|
417
|
+
const { isAuthenticated } = useAuth()
|
|
418
|
+
|
|
419
|
+
if (!isAuthenticated) {
|
|
420
|
+
return <Navigate to="/login" />
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
return <div>Protected Content</div>
|
|
424
|
+
}
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
> 주의: Navigate 컴포넌트는 클라이언트 전용. 서버 사이드 리다이렉트가 필요하면 beforeLoad에서 `redirect()` throw 사용.
|
|
428
|
+
|
|
429
|
+
</navigate_component>
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
<match_route>
|
|
434
|
+
|
|
435
|
+
## useMatchRoute / MatchRoute: 라우트 매칭 확인
|
|
436
|
+
|
|
437
|
+
현재 경로가 특정 라우트와 매칭되는지 확인. 낙관적 UI에 유용.
|
|
438
|
+
|
|
439
|
+
```tsx
|
|
440
|
+
import { MatchRoute, useMatchRoute } from '@tanstack/react-router'
|
|
441
|
+
|
|
442
|
+
// 컴포넌트 방식: pending 상태 표시
|
|
443
|
+
const NavItem = () => (
|
|
444
|
+
<Link to="/users">
|
|
445
|
+
Users
|
|
446
|
+
<MatchRoute to="/users" pending>
|
|
447
|
+
<Spinner />
|
|
448
|
+
</MatchRoute>
|
|
449
|
+
</Link>
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
// 함수 children 방식
|
|
453
|
+
const NavItem2 = () => (
|
|
454
|
+
<Link to="/users">
|
|
455
|
+
Users
|
|
456
|
+
<MatchRoute to="/users" pending>
|
|
457
|
+
{(match) => <Spinner show={match} />}
|
|
458
|
+
</MatchRoute>
|
|
459
|
+
</Link>
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
// 훅 방식: 프로그래매틱 체크
|
|
463
|
+
const Component = () => {
|
|
464
|
+
const matchRoute = useMatchRoute()
|
|
465
|
+
|
|
466
|
+
useEffect(() => {
|
|
467
|
+
if (matchRoute({ to: '/users', pending: true })) {
|
|
468
|
+
console.info('/users 라우트가 매칭되고 전환 중')
|
|
49
469
|
}
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
return <div />
|
|
473
|
+
}
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
</match_route>
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
<programmatic_patterns>
|
|
481
|
+
|
|
482
|
+
## 실전 패턴
|
|
483
|
+
|
|
484
|
+
### 조건부 네비게이션
|
|
485
|
+
|
|
486
|
+
```tsx
|
|
487
|
+
const Form = () => {
|
|
488
|
+
const navigate = useNavigate()
|
|
489
|
+
const [errors, setErrors] = useState<Record<string, string>>({})
|
|
490
|
+
|
|
491
|
+
const handleSubmit = async (data: FormData) => {
|
|
492
|
+
const result = await validate(data)
|
|
493
|
+
|
|
494
|
+
if (!result.success) {
|
|
495
|
+
setErrors(result.errors)
|
|
496
|
+
return // 에러 있으면 네비게이션 안 함
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
navigate({ to: '/confirmation', search: { orderId: result.id } })
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
return <form onSubmit={handleSubmit}>{/* ... */}</form>
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
### 뒤로 가기 (검증 필수)
|
|
507
|
+
|
|
508
|
+
```tsx
|
|
509
|
+
const BackButton = () => {
|
|
510
|
+
const navigate = useNavigate()
|
|
511
|
+
|
|
512
|
+
return (
|
|
513
|
+
<button onClick={() => navigate({ to: '..' })}>
|
|
514
|
+
Back
|
|
515
|
+
</button>
|
|
516
|
+
)
|
|
517
|
+
}
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### 폼 제출 후 상세 페이지로 이동
|
|
521
|
+
|
|
522
|
+
```tsx
|
|
523
|
+
const CreatePost = () => {
|
|
524
|
+
const navigate = useNavigate()
|
|
525
|
+
const createMutation = useMutation({
|
|
526
|
+
mutationFn: createPost,
|
|
527
|
+
onSuccess: (newPost) => {
|
|
528
|
+
// 생성된 post ID로 상세 페이지로 이동
|
|
529
|
+
navigate({
|
|
530
|
+
to: '/posts/$postId',
|
|
531
|
+
params: { postId: newPost.id },
|
|
532
|
+
})
|
|
533
|
+
},
|
|
534
|
+
})
|
|
535
|
+
|
|
536
|
+
return (
|
|
537
|
+
<button onClick={() => createMutation.mutate({ title: 'New Post' })}>
|
|
538
|
+
Create
|
|
539
|
+
</button>
|
|
540
|
+
)
|
|
541
|
+
}
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
### Search params로 필터 상태 유지
|
|
545
|
+
|
|
546
|
+
```tsx
|
|
547
|
+
const FilterableList = () => {
|
|
548
|
+
const navigate = useNavigate()
|
|
549
|
+
const { category, sort } = Route.useSearch()
|
|
550
|
+
|
|
551
|
+
const handleFilter = (newCategory: string) => {
|
|
552
|
+
navigate({
|
|
553
|
+
to: '/items',
|
|
554
|
+
search: prev => ({
|
|
555
|
+
...prev,
|
|
556
|
+
category: newCategory,
|
|
557
|
+
page: 1, // 필터 변경 시 페이지 1로 리셋
|
|
558
|
+
}),
|
|
559
|
+
})
|
|
50
560
|
}
|
|
51
561
|
|
|
52
|
-
return
|
|
562
|
+
return (
|
|
563
|
+
<select value={category} onChange={e => handleFilter(e.target.value)}>
|
|
564
|
+
<option value="all">All</option>
|
|
565
|
+
<option value="electronics">Electronics</option>
|
|
566
|
+
</select>
|
|
567
|
+
)
|
|
53
568
|
}
|
|
54
569
|
```
|
|
55
570
|
|
|
56
|
-
|
|
571
|
+
### 선택적 파라미터로 필터 네비게이션
|
|
572
|
+
|
|
573
|
+
```tsx
|
|
574
|
+
const FilterNav = () => {
|
|
575
|
+
const navigate = useNavigate()
|
|
576
|
+
|
|
577
|
+
// 필터 초기화
|
|
578
|
+
const clearFilters = () => {
|
|
579
|
+
navigate({
|
|
580
|
+
to: '/posts/{-$category}/{-$tag}',
|
|
581
|
+
params: { category: undefined, tag: undefined },
|
|
582
|
+
})
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// 특정 카테고리 설정
|
|
586
|
+
const setCategory = (category: string) => {
|
|
587
|
+
navigate({
|
|
588
|
+
to: '/posts/{-$category}/{-$tag}',
|
|
589
|
+
params: prev => ({ ...prev, category }),
|
|
590
|
+
})
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
return (
|
|
594
|
+
<div>
|
|
595
|
+
<button onClick={() => setCategory('tech')}>Tech</button>
|
|
596
|
+
<button onClick={clearFilters}>Clear</button>
|
|
597
|
+
</div>
|
|
598
|
+
)
|
|
599
|
+
}
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
</programmatic_patterns>
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
<type_safe_routing>
|
|
607
|
+
|
|
608
|
+
## 타입 안전 라우팅
|
|
609
|
+
|
|
610
|
+
TanStack Router는 경로와 파라미터를 타입 체크한다.
|
|
611
|
+
|
|
612
|
+
### Link 타입 체크
|
|
613
|
+
|
|
614
|
+
```tsx
|
|
615
|
+
// 올바른 예시
|
|
616
|
+
<Link to="/posts/$postId" params={{ postId: '123' }}>
|
|
617
|
+
// 타입 체크: postId 필수
|
|
618
|
+
</Link>
|
|
619
|
+
|
|
620
|
+
<Link to="/about">
|
|
621
|
+
// params 불필요
|
|
622
|
+
</Link>
|
|
623
|
+
|
|
624
|
+
// route.to로 타입 안전 참조
|
|
625
|
+
import { Route as aboutRoute } from './routes/about'
|
|
626
|
+
<Link to={aboutRoute.to}>About</Link>
|
|
627
|
+
|
|
628
|
+
// 오류 예시
|
|
629
|
+
<Link to="/posts/$postId">
|
|
630
|
+
// TS Error: params 필수
|
|
631
|
+
</Link>
|
|
632
|
+
|
|
633
|
+
<Link to="/posts" params={{ postId: '123' }}>
|
|
634
|
+
// TS Error: /posts는 파라미터 없음
|
|
635
|
+
</Link>
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
### useNavigate 타입 체크 (from 파라미터)
|
|
639
|
+
|
|
640
|
+
```tsx
|
|
641
|
+
// `/posts/$postId` 라우트 내부
|
|
642
|
+
export const Route = createFileRoute('/posts/$postId')({
|
|
643
|
+
component: PostDetail,
|
|
644
|
+
})
|
|
645
|
+
|
|
646
|
+
const PostDetail = () => {
|
|
647
|
+
// from 명시: 이 라우트 내에서만 호출 가능
|
|
648
|
+
const navigate = useNavigate({ from: '/posts/$postId' })
|
|
649
|
+
|
|
650
|
+
const goRelated = (id: string) => {
|
|
651
|
+
navigate({
|
|
652
|
+
to: '/posts/$postId',
|
|
653
|
+
params: { postId: id }, // 타입 체크됨
|
|
654
|
+
})
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
</type_safe_routing>
|
|
660
|
+
|
|
661
|
+
---
|
|
57
662
|
|
|
58
|
-
<
|
|
663
|
+
<comparison>
|
|
59
664
|
|
|
60
|
-
|
|
61
|
-
|------------|------|------|
|
|
62
|
-
| `to` | string | 목적지 경로 |
|
|
63
|
-
| `params` | object | Path 파라미터 |
|
|
64
|
-
| `search` | object \| function | Search params |
|
|
65
|
-
| `hash` | string | Hash |
|
|
66
|
-
| `replace` | boolean | history replace |
|
|
67
|
-
| `preload` | 'intent' \| 'render' \| 'viewport' | Preload 전략 |
|
|
68
|
-
| `activeProps` | object | Active 시 props |
|
|
69
|
-
| `inactiveProps` | object | Inactive 시 props |
|
|
665
|
+
## Link vs useNavigate vs Navigate vs router.navigate
|
|
70
666
|
|
|
71
|
-
|
|
|
72
|
-
|
|
73
|
-
|
|
|
74
|
-
| `
|
|
75
|
-
|
|
|
76
|
-
| `
|
|
77
|
-
|
|
|
78
|
-
| `
|
|
667
|
+
| 상황 | 추천 | 이유 |
|
|
668
|
+
|------|------|------|
|
|
669
|
+
| HTML 선언 | `<Link>` | 자동 타입 체크, 접근성 (href), cmd/ctrl+click |
|
|
670
|
+
| 이벤트 핸들러 | `useNavigate()` | 조건부 로직 가능 |
|
|
671
|
+
| 호버 preload | `<Link preload="intent">` | 자동으로 효율적 |
|
|
672
|
+
| 비동기 후 네비게이션 | `useNavigate()` + startTransition | 상태 동기화 |
|
|
673
|
+
| 마운트 시 즉시 리다이렉트 | `<Navigate>` | useEffect 불필요 |
|
|
674
|
+
| 프레임워크 외부 | `router.navigate()` | 어디서든 사용 가능 |
|
|
675
|
+
| 동적 파라미터 | 모두 가능 | 문맥에 따라 |
|
|
676
|
+
| 낙관적 pending UI | `<MatchRoute pending>` | 전환 중 스피너 |
|
|
79
677
|
|
|
80
|
-
</
|
|
678
|
+
</comparison>
|