@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.
Files changed (170) hide show
  1. package/dist/index.js +7 -1
  2. package/package.json +1 -1
  3. package/templates/.claude/agents/analyst.md +5 -0
  4. package/templates/.claude/agents/architect.md +5 -0
  5. package/templates/.claude/agents/build-fixer.md +1 -0
  6. package/templates/.claude/agents/code-reviewer.md +1 -0
  7. package/templates/.claude/agents/critic.md +4 -0
  8. package/templates/.claude/agents/deep-executor.md +1 -0
  9. package/templates/.claude/agents/dependency-manager.md +2 -0
  10. package/templates/.claude/agents/deployment-validator.md +2 -0
  11. package/templates/.claude/agents/designer.md +2 -0
  12. package/templates/.claude/agents/document-writer.md +3 -0
  13. package/templates/.claude/agents/explore.md +1 -0
  14. package/templates/.claude/agents/git-operator.md +2 -0
  15. package/templates/.claude/agents/implementation-executor.md +2 -0
  16. package/templates/.claude/agents/ko-to-en-translator.md +3 -0
  17. package/templates/.claude/agents/lint-fixer.md +2 -0
  18. package/templates/.claude/agents/planner.md +3 -0
  19. package/templates/.claude/agents/pm.md +349 -0
  20. package/templates/.claude/agents/qa-tester.md +1 -0
  21. package/templates/.claude/agents/refactor-advisor.md +4 -0
  22. package/templates/.claude/agents/researcher.md +9 -1
  23. package/templates/.claude/agents/scientist.md +1 -0
  24. package/templates/.claude/agents/security-reviewer.md +1 -0
  25. package/templates/.claude/agents/tdd-guide.md +1 -0
  26. package/templates/.claude/agents/vision.md +1 -0
  27. package/templates/.claude/instructions/agent-patterns/agent-teams-usage.md +376 -0
  28. package/templates/.claude/instructions/sourcing/reliable-search.md +49 -2
  29. package/templates/.claude/scripts/agent-teams/check-availability.sh +238 -0
  30. package/templates/.claude/scripts/agent-teams/setup-tmux.sh +125 -0
  31. package/templates/.claude/skills/agent-teams-setup/SKILL.md +460 -0
  32. package/templates/.claude/skills/brainstorm/SKILL.md +1 -0
  33. package/templates/.claude/skills/bug-fix/SKILL.md +1 -0
  34. package/templates/.claude/skills/crawler/SKILL.md +2 -0
  35. package/templates/.claude/skills/docs-creator/SKILL.md +1 -0
  36. package/templates/.claude/skills/docs-fetch/SKILL.md +6 -4
  37. package/templates/.claude/skills/docs-refactor/SKILL.md +1 -0
  38. package/templates/.claude/skills/elon-musk/SKILL.md +1 -0
  39. package/templates/.claude/skills/execute/SKILL.md +1 -0
  40. package/templates/.claude/skills/feedback/SKILL.md +1 -0
  41. package/templates/.claude/skills/figma-to-code/SKILL.md +1 -0
  42. package/templates/.claude/skills/genius-thinking/SKILL.md +1 -0
  43. package/templates/.claude/skills/global-uiux-design/SKILL.md +1 -0
  44. package/templates/.claude/skills/korea-uiux-design/SKILL.md +1 -0
  45. package/templates/.claude/skills/nextjs-react-best-practices/SKILL.md +1 -0
  46. package/templates/.claude/skills/plan/SKILL.md +1 -0
  47. package/templates/.claude/skills/prd/SKILL.md +1 -0
  48. package/templates/.claude/skills/project-optimizer/AGENTS.md +275 -0
  49. package/templates/.claude/skills/project-optimizer/SKILL.md +375 -0
  50. package/templates/.claude/skills/project-optimizer/rules/arch-config-centralize.md +66 -0
  51. package/templates/.claude/skills/project-optimizer/rules/arch-hot-path.md +35 -0
  52. package/templates/.claude/skills/project-optimizer/rules/arch-interface-segregation.md +51 -0
  53. package/templates/.claude/skills/project-optimizer/rules/arch-module-boundary.md +42 -0
  54. package/templates/.claude/skills/project-optimizer/rules/build-cache.md +57 -0
  55. package/templates/.claude/skills/project-optimizer/rules/build-code-split.md +56 -0
  56. package/templates/.claude/skills/project-optimizer/rules/build-incremental.md +65 -0
  57. package/templates/.claude/skills/project-optimizer/rules/build-minify.md +61 -0
  58. package/templates/.claude/skills/project-optimizer/rules/build-tree-shake.md +60 -0
  59. package/templates/.claude/skills/project-optimizer/rules/code-complexity.md +65 -0
  60. package/templates/.claude/skills/project-optimizer/rules/code-dead-elimination.md +32 -0
  61. package/templates/.claude/skills/project-optimizer/rules/code-duplication.md +54 -0
  62. package/templates/.claude/skills/project-optimizer/rules/code-error-handling.md +75 -0
  63. package/templates/.claude/skills/project-optimizer/rules/code-naming.md +52 -0
  64. package/templates/.claude/skills/project-optimizer/rules/concurrency-defer-await.md +54 -0
  65. package/templates/.claude/skills/project-optimizer/rules/concurrency-parallel.md +90 -0
  66. package/templates/.claude/skills/project-optimizer/rules/concurrency-pipeline.md +68 -0
  67. package/templates/.claude/skills/project-optimizer/rules/concurrency-pool.md +68 -0
  68. package/templates/.claude/skills/project-optimizer/rules/deps-lightweight-alt.md +37 -0
  69. package/templates/.claude/skills/project-optimizer/rules/deps-peer-align.md +44 -0
  70. package/templates/.claude/skills/project-optimizer/rules/deps-security-audit.md +45 -0
  71. package/templates/.claude/skills/project-optimizer/rules/deps-unused-removal.md +25 -0
  72. package/templates/.claude/skills/project-optimizer/rules/deps-version-pin.md +40 -0
  73. package/templates/.claude/skills/project-optimizer/rules/dx-ci-speed.md +47 -0
  74. package/templates/.claude/skills/project-optimizer/rules/dx-dev-server.md +35 -0
  75. package/templates/.claude/skills/project-optimizer/rules/dx-lint-config.md +36 -0
  76. package/templates/.claude/skills/project-optimizer/rules/dx-test-coverage.md +34 -0
  77. package/templates/.claude/skills/project-optimizer/rules/dx-type-safety.md +49 -0
  78. package/templates/.claude/skills/project-optimizer/rules/io-batch-queries.md +67 -0
  79. package/templates/.claude/skills/project-optimizer/rules/io-cache-layer.md +67 -0
  80. package/templates/.claude/skills/project-optimizer/rules/io-connection-reuse.md +67 -0
  81. package/templates/.claude/skills/project-optimizer/rules/io-serialize-minimal.md +61 -0
  82. package/templates/.claude/skills/project-optimizer/rules/io-stream.md +75 -0
  83. package/templates/.claude/skills/project-optimizer/rules/memory-bounded-cache.md +65 -0
  84. package/templates/.claude/skills/project-optimizer/rules/memory-large-data.md +64 -0
  85. package/templates/.claude/skills/project-optimizer/rules/memory-lazy-init.md +78 -0
  86. package/templates/.claude/skills/project-optimizer/rules/memory-leak-prevention.md +79 -0
  87. package/templates/.claude/skills/project-optimizer/rules/memory-pool-reuse.md +70 -0
  88. package/templates/.claude/skills/ralph/SKILL.md +1 -0
  89. package/templates/.claude/skills/refactor/SKILL.md +1 -0
  90. package/templates/.claude/skills/research/SKILL.md +1 -0
  91. package/templates/.claude/skills/sql-optimizer/SKILL.md +438 -0
  92. package/templates/.claude/skills/sql-optimizer/orm-patterns.md +218 -0
  93. package/templates/.claude/skills/startup-validator/SKILL.md +1 -0
  94. package/templates/.claude/skills/tanstack-start-react-best-practices/AGENTS.md +53 -14
  95. package/templates/.claude/skills/tanstack-start-react-best-practices/SKILL.md +94 -27
  96. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-defer-third-party.md +42 -19
  97. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-optimistic-updates.md +109 -0
  98. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-suspense-query.md +74 -0
  99. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-use-hook.md +81 -0
  100. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-react-compiler.md +81 -0
  101. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-beforeload-auth.md +121 -0
  102. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-file-conventions.md +104 -0
  103. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-link-navigation.md +119 -0
  104. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-nested-layouts.md +155 -0
  105. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-path-params.md +89 -0
  106. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-pending-component.md +110 -0
  107. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-preload-strategy.md +91 -0
  108. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-router-context.md +120 -0
  109. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-search-params.md +114 -0
  110. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-deferred-data.md +1 -1
  111. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-error-boundaries.md +79 -0
  112. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-middleware.md +85 -0
  113. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-serialization.md +56 -21
  114. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-streaming.md +84 -0
  115. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-validator.md +71 -0
  116. package/templates/.claude/skills/tauri-react-best-practices/AGENTS.md +527 -0
  117. package/templates/.claude/skills/tauri-react-best-practices/SKILL.md +571 -0
  118. package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-barrel-imports.md +140 -0
  119. package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-cargo-profile.md +96 -0
  120. package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-frontend-treeshake.md +242 -0
  121. package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-lazy-components.md +255 -0
  122. package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-remove-unused-commands.md +160 -0
  123. package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-ci-pipeline.md +269 -0
  124. package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-signing.md +207 -0
  125. package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-updater.md +226 -0
  126. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-async-commands.md +172 -0
  127. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-batch-commands.md +133 -0
  128. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-binary-response.md +198 -0
  129. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-channel-streaming.md +186 -0
  130. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-error-handling.md +250 -0
  131. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-type-safe.md +227 -0
  132. package/templates/.claude/skills/tauri-react-best-practices/rules/perf-derived-state.md +231 -0
  133. package/templates/.claude/skills/tauri-react-best-practices/rules/perf-functional-setstate.md +191 -0
  134. package/templates/.claude/skills/tauri-react-best-practices/rules/perf-index-maps.md +276 -0
  135. package/templates/.claude/skills/tauri-react-best-practices/rules/perf-lazy-state-init.md +196 -0
  136. package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-lifecycle.md +265 -0
  137. package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-mobile-compat.md +199 -0
  138. package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-permission-scope.md +193 -0
  139. package/templates/.claude/skills/tauri-react-best-practices/rules/react-error-boundary.md +239 -0
  140. package/templates/.claude/skills/tauri-react-best-practices/rules/react-event-listener.md +151 -0
  141. package/templates/.claude/skills/tauri-react-best-practices/rules/react-file-src.md +155 -0
  142. package/templates/.claude/skills/tauri-react-best-practices/rules/react-invoke-hook.md +139 -0
  143. package/templates/.claude/skills/tauri-react-best-practices/rules/react-optimistic-update.md +211 -0
  144. package/templates/.claude/skills/tauri-react-best-practices/rules/security-capability-split.md +205 -0
  145. package/templates/.claude/skills/tauri-react-best-practices/rules/security-csp.md +207 -0
  146. package/templates/.claude/skills/tauri-react-best-practices/rules/security-least-privilege.md +106 -0
  147. package/templates/.claude/skills/tauri-react-best-practices/rules/security-no-wildcard.md +253 -0
  148. package/templates/.claude/skills/tauri-react-best-practices/rules/security-scope-paths.md +160 -0
  149. package/templates/.claude/skills/tauri-react-best-practices/rules/state-async-mutex.md +270 -0
  150. package/templates/.claude/skills/tauri-react-best-practices/rules/state-mutex-pattern.md +265 -0
  151. package/templates/.claude/skills/tauri-react-best-practices/rules/state-react-sync.md +375 -0
  152. package/templates/.claude/skills/tauri-react-best-practices/rules/state-single-container.md +275 -0
  153. package/templates/tanstack-start/docs/architecture.md +238 -167
  154. package/templates/tanstack-start/docs/library/tanstack-router/error-handling.md +777 -38
  155. package/templates/tanstack-start/docs/library/tanstack-router/hooks.md +549 -37
  156. package/templates/tanstack-start/docs/library/tanstack-router/index.md +895 -111
  157. package/templates/tanstack-start/docs/library/tanstack-router/navigation.md +641 -43
  158. package/templates/tanstack-start/docs/library/tanstack-router/route-context.md +889 -38
  159. package/templates/tanstack-start/docs/library/tanstack-router/search-params.md +891 -29
  160. package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +972 -36
  161. package/templates/tanstack-start/docs/library/tanstack-start/index.md +1525 -881
  162. package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +1099 -20
  163. package/templates/tanstack-start/docs/library/tanstack-start/routing.md +796 -30
  164. package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +953 -35
  165. package/templates/tanstack-start/docs/library/tanstack-start/setup.md +371 -15
  166. package/templates/tauri/CLAUDE.md +189 -0
  167. package/templates/tauri/docs/guides/distribution.md +261 -0
  168. package/templates/tauri/docs/guides/getting-started.md +302 -0
  169. package/templates/tauri/docs/guides/mobile.md +288 -0
  170. package/templates/tauri/docs/library/tauri/index.md +510 -0
@@ -0,0 +1,276 @@
1
+ # 반복 조회용 Map 빌드
2
+
3
+ ## 왜 중요한가
4
+
5
+ 동일한 키로 배열을 여러 번 `.find()` 조회하면 O(n) 복잡도가 반복됩니다. Map을 사용하면 O(1) 조회로 성능을 크게 개선할 수 있습니다. Tauri 앱에서는 파일 목록, 사용자 목록, 설정 데이터 등을 처리할 때 특히 유용합니다.
6
+
7
+ ## ❌ 잘못된 패턴
8
+
9
+ ```tsx
10
+ import { invoke } from '@tauri-apps/api/core'
11
+ import { useEffect, useState } from 'react'
12
+
13
+ type Order = { id: string; userId: string; total: number }
14
+ type User = { id: string; name: string; email: string }
15
+
16
+ function OrderList() {
17
+ const [orders, setOrders] = useState<Order[]>([])
18
+ const [users, setUsers] = useState<User[]>([])
19
+
20
+ useEffect(() => {
21
+ Promise.all([
22
+ invoke<Order[]>('get_orders'),
23
+ invoke<User[]>('get_users')
24
+ ]).then(([ordersData, usersData]) => {
25
+ setOrders(ordersData)
26
+ setUsers(usersData)
27
+ })
28
+ }, [])
29
+
30
+ return (
31
+ <div>
32
+ {orders.map(order => {
33
+ // ❌ 매 order마다 O(n) 조회
34
+ const user = users.find(u => u.id === order.userId)
35
+ return (
36
+ <div key={order.id}>
37
+ Order #{order.id} - {user?.name} - ${order.total}
38
+ </div>
39
+ )
40
+ })}
41
+ </div>
42
+ )
43
+ }
44
+
45
+ // 1000개 주문 × 1000명 사용자 = 1,000,000 연산
46
+ ```
47
+
48
+ **문제점:**
49
+ - 매 렌더링마다 O(n) 조회 반복
50
+ - 큰 데이터셋에서 성능 저하
51
+ - 1000 orders × 1000 users = 1M 연산
52
+
53
+ ## ✅ 올바른 패턴
54
+
55
+ ```tsx
56
+ import { invoke } from '@tauri-apps/api/core'
57
+ import { useEffect, useState, useMemo } from 'react'
58
+
59
+ type Order = { id: string; userId: string; total: number }
60
+ type User = { id: string; name: string; email: string }
61
+
62
+ function OrderList() {
63
+ const [orders, setOrders] = useState<Order[]>([])
64
+ const [users, setUsers] = useState<User[]>([])
65
+
66
+ useEffect(() => {
67
+ Promise.all([
68
+ invoke<Order[]>('get_orders'),
69
+ invoke<User[]>('get_users')
70
+ ]).then(([ordersData, usersData]) => {
71
+ setOrders(ordersData)
72
+ setUsers(usersData)
73
+ })
74
+ }, [])
75
+
76
+ // ✅ Map을 한 번만 생성 (O(n))
77
+ const userById = useMemo(
78
+ () => new Map(users.map(u => [u.id, u])),
79
+ [users]
80
+ )
81
+
82
+ return (
83
+ <div>
84
+ {orders.map(order => {
85
+ // ✅ O(1) 조회
86
+ const user = userById.get(order.userId)
87
+ return (
88
+ <div key={order.id}>
89
+ Order #{order.id} - {user?.name} - ${order.total}
90
+ </div>
91
+ )
92
+ })}
93
+ </div>
94
+ )
95
+ }
96
+
97
+ // 1000개 주문 + 1000명 사용자 = 2,000 연산
98
+ ```
99
+
100
+ **파일 경로 인덱싱:**
101
+
102
+ ```tsx
103
+ import { invoke } from '@tauri-apps/api/core'
104
+ import { useEffect, useState, useMemo } from 'react'
105
+
106
+ type FileMetadata = {
107
+ path: string
108
+ size: number
109
+ modified: string
110
+ }
111
+
112
+ function FileExplorer() {
113
+ const [files, setFiles] = useState<FileMetadata[]>([])
114
+ const [selectedPaths, setSelectedPaths] = useState<string[]>([])
115
+
116
+ useEffect(() => {
117
+ invoke<FileMetadata[]>('list_files').then(setFiles)
118
+ }, [])
119
+
120
+ // ✅ 파일 경로로 Map 생성
121
+ const fileByPath = useMemo(
122
+ () => new Map(files.map(f => [f.path, f])),
123
+ [files]
124
+ )
125
+
126
+ return (
127
+ <div>
128
+ <h2>Selected Files</h2>
129
+ {selectedPaths.map(path => {
130
+ // ✅ O(1) 조회
131
+ const file = fileByPath.get(path)
132
+ return file ? (
133
+ <div key={path}>
134
+ {path} - {file.size} bytes
135
+ </div>
136
+ ) : null
137
+ })}
138
+ </div>
139
+ )
140
+ }
141
+ ```
142
+
143
+ **다중 키 인덱싱:**
144
+
145
+ ```tsx
146
+ import { useMemo } from 'react'
147
+
148
+ type Product = {
149
+ id: string
150
+ sku: string
151
+ name: string
152
+ price: number
153
+ }
154
+
155
+ function ProductCatalog({ products }: { products: Product[] }) {
156
+ // ✅ ID로 인덱싱
157
+ const productById = useMemo(
158
+ () => new Map(products.map(p => [p.id, p])),
159
+ [products]
160
+ )
161
+
162
+ // ✅ SKU로 인덱싱
163
+ const productBySku = useMemo(
164
+ () => new Map(products.map(p => [p.sku, p])),
165
+ [products]
166
+ )
167
+
168
+ const getProductById = (id: string) => productById.get(id)
169
+ const getProductBySku = (sku: string) => productBySku.get(sku)
170
+
171
+ return <div>...</div>
172
+ }
173
+ ```
174
+
175
+ **그룹화 Map:**
176
+
177
+ ```tsx
178
+ import { invoke } from '@tauri-apps/api/core'
179
+ import { useEffect, useState, useMemo } from 'react'
180
+
181
+ type File = {
182
+ path: string
183
+ extension: string
184
+ size: number
185
+ }
186
+
187
+ function FilesByExtension() {
188
+ const [files, setFiles] = useState<File[]>([])
189
+
190
+ useEffect(() => {
191
+ invoke<File[]>('list_files').then(setFiles)
192
+ }, [])
193
+
194
+ // ✅ 확장자별로 그룹화
195
+ const filesByExt = useMemo(() => {
196
+ const map = new Map<string, File[]>()
197
+ files.forEach(file => {
198
+ const existing = map.get(file.extension) || []
199
+ map.set(file.extension, [...existing, file])
200
+ })
201
+ return map
202
+ }, [files])
203
+
204
+ return (
205
+ <div>
206
+ {Array.from(filesByExt.entries()).map(([ext, files]) => (
207
+ <div key={ext}>
208
+ <h3>{ext} ({files.length} files)</h3>
209
+ {files.map(file => (
210
+ <div key={file.path}>{file.path}</div>
211
+ ))}
212
+ </div>
213
+ ))}
214
+ </div>
215
+ )
216
+ }
217
+ ```
218
+
219
+ **Set으로 존재 여부 체크:**
220
+
221
+ ```tsx
222
+ import { useMemo } from 'react'
223
+
224
+ type FileItem = { path: string; selected: boolean }
225
+
226
+ function FileList({ files }: { files: FileItem[] }) {
227
+ // ✅ Set으로 O(1) 체크
228
+ const selectedPaths = useMemo(
229
+ () => new Set(files.filter(f => f.selected).map(f => f.path)),
230
+ [files]
231
+ )
232
+
233
+ const isSelected = (path: string) => selectedPaths.has(path) // O(1)
234
+
235
+ return (
236
+ <div>
237
+ {files.map(file => (
238
+ <div key={file.path} className={isSelected(file.path) ? 'selected' : ''}>
239
+ {file.path}
240
+ </div>
241
+ ))}
242
+ </div>
243
+ )
244
+ }
245
+ ```
246
+
247
+ ## 추가 컨텍스트
248
+
249
+ **성능 비교:**
250
+
251
+ | 데이터 크기 | Array.find() | Map.get() | 개선율 |
252
+ |-------------|--------------|-----------|--------|
253
+ | 100 items | 5,000 ops | 100 ops | 50x |
254
+ | 1,000 items | 500,000 ops | 1,000 ops | 500x |
255
+ | 10,000 items | 50,000,000 ops | 10,000 ops | 5000x |
256
+
257
+ **Map vs Object:**
258
+ - Map은 키로 객체 사용 가능
259
+ - Map은 순서 보장 (insertion order)
260
+ - Map은 size 프로퍼티 제공
261
+ - Map은 iterate 최적화
262
+
263
+ **언제 사용:**
264
+ - 반복 조회가 필요한 경우
265
+ - 배열 크기가 큰 경우 (100개 이상)
266
+ - 조회 빈도가 높은 경우
267
+ - 성능이 중요한 렌더링 로직
268
+
269
+ **언제 불필요:**
270
+ - 1회성 조회
271
+ - 작은 배열 (10개 이하)
272
+ - Map 생성 비용이 조회 비용보다 큰 경우
273
+
274
+ **참고:** [MDN Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
275
+
276
+ 영향도: LOW-MEDIUM - 대규모 데이터 처리 성능 개선
@@ -0,0 +1,196 @@
1
+ # 비싼 초기값은 함수로 전달
2
+
3
+ ## 왜 중요한가
4
+
5
+ `useState`에 비용이 큰 초기 값을 직접 전달하면 매 렌더링마다 실행됩니다. 초기화 후에는 사용되지 않지만 계산 비용이 낭비됩니다. Tauri 앱에서는 IPC 호출, 파일 읽기, 데이터 구조 변환 등이 이에 해당합니다.
6
+
7
+ ## ❌ 잘못된 패턴
8
+
9
+ ```tsx
10
+ import { invoke } from '@tauri-apps/api/core'
11
+ import { readTextFile } from '@tauri-apps/plugin-fs'
12
+ import { useState, useEffect } from 'react'
13
+
14
+ function ConfigEditor() {
15
+ // ❌ JSON.parse가 매 렌더링마다 실행됨
16
+ const [config, setConfig] = useState(
17
+ JSON.parse(localStorage.getItem('config') || '{}')
18
+ )
19
+
20
+ return <div>{JSON.stringify(config)}</div>
21
+ }
22
+
23
+ function FileSearch({ files }: { files: string[] }) {
24
+ // ❌ buildSearchIndex()가 매 렌더링마다 실행됨
25
+ const [searchIndex, setSearchIndex] = useState(
26
+ buildSearchIndex(files)
27
+ )
28
+
29
+ return <SearchBar index={searchIndex} />
30
+ }
31
+
32
+ function buildSearchIndex(files: string[]) {
33
+ console.log('Building index...') // 매 렌더링마다 출력
34
+ return files.reduce((acc, file) => {
35
+ acc[file.toLowerCase()] = file
36
+ return acc
37
+ }, {} as Record<string, string>)
38
+ }
39
+ ```
40
+
41
+ **문제점:**
42
+ - 초기화 후에도 매 렌더링마다 불필요한 계산 실행
43
+ - 성능 낭비 (특히 대규모 데이터 처리 시)
44
+ - 콘솔 로그가 반복 출력
45
+
46
+ ## ✅ 올바른 패턴
47
+
48
+ ```tsx
49
+ import { invoke } from '@tauri-apps/api/core'
50
+ import { readTextFile } from '@tauri-apps/plugin-fs'
51
+ import { useState, useEffect } from 'react'
52
+
53
+ function ConfigEditor() {
54
+ // ✅ JSON.parse가 초기 렌더링 시에만 실행됨
55
+ const [config, setConfig] = useState(() => {
56
+ const stored = localStorage.getItem('config')
57
+ return stored ? JSON.parse(stored) : {}
58
+ })
59
+
60
+ return <div>{JSON.stringify(config)}</div>
61
+ }
62
+
63
+ function FileSearch({ files }: { files: string[] }) {
64
+ // ✅ buildSearchIndex()가 초기 렌더링 시에만 실행됨
65
+ const [searchIndex, setSearchIndex] = useState(() =>
66
+ buildSearchIndex(files)
67
+ )
68
+
69
+ return <SearchBar index={searchIndex} />
70
+ }
71
+
72
+ function buildSearchIndex(files: string[]) {
73
+ console.log('Building index...') // 초기 렌더링 시에만 출력
74
+ return files.reduce((acc, file) => {
75
+ acc[file.toLowerCase()] = file
76
+ return acc
77
+ }, {} as Record<string, string>)
78
+ }
79
+ ```
80
+
81
+ **Tauri 파일 시스템 읽기:**
82
+
83
+ ```tsx
84
+ import { readTextFile } from '@tauri-apps/plugin-fs'
85
+ import { appDataDir, join } from '@tauri-apps/api/path'
86
+ import { useState, useEffect } from 'react'
87
+
88
+ function UserSettings() {
89
+ const [settings, setSettings] = useState<Settings | null>(null)
90
+
91
+ useEffect(() => {
92
+ // ✅ 비동기 초기화는 useEffect에서
93
+ (async () => {
94
+ const dataDir = await appDataDir()
95
+ const configPath = await join(dataDir, 'settings.json')
96
+ const content = await readTextFile(configPath)
97
+ setSettings(JSON.parse(content))
98
+ })()
99
+ }, [])
100
+
101
+ if (!settings) return <div>Loading...</div>
102
+ return <div>{JSON.stringify(settings)}</div>
103
+ }
104
+ ```
105
+
106
+ **Tauri invoke 결과 캐싱:**
107
+
108
+ ```tsx
109
+ import { invoke } from '@tauri-apps/api/core'
110
+ import { useState, useEffect } from 'react'
111
+
112
+ function FileTree() {
113
+ // ✅ 비동기 데이터는 null로 초기화 후 useEffect에서 로드
114
+ const [tree, setTree] = useState<FileNode | null>(null)
115
+
116
+ useEffect(() => {
117
+ invoke<FileNode>('get_file_tree').then(setTree)
118
+ }, [])
119
+
120
+ if (!tree) return <div>Loading...</div>
121
+
122
+ // ✅ 계산 비용이 큰 변환은 지연 초기화
123
+ const [flatList, setFlatList] = useState(() =>
124
+ flattenTree(tree) // 초기 렌더링 시에만 실행
125
+ )
126
+
127
+ return <TreeView tree={tree} />
128
+ }
129
+
130
+ function flattenTree(node: FileNode): string[] {
131
+ console.log('Flattening tree...')
132
+ const result: string[] = []
133
+ const stack = [node]
134
+ while (stack.length > 0) {
135
+ const current = stack.pop()!
136
+ result.push(current.path)
137
+ if (current.children) stack.push(...current.children)
138
+ }
139
+ return result
140
+ }
141
+ ```
142
+
143
+ **Map/Set 초기화:**
144
+
145
+ ```tsx
146
+ import { useState } from 'react'
147
+
148
+ type Item = { id: string; name: string }
149
+
150
+ function ItemList({ items }: { items: Item[] }) {
151
+ // ✅ Map 생성이 초기 렌더링 시에만 실행됨
152
+ const [itemMap, setItemMap] = useState(() =>
153
+ new Map(items.map(item => [item.id, item]))
154
+ )
155
+
156
+ // ✅ Set 생성이 초기 렌더링 시에만 실행됨
157
+ const [selectedIds, setSelectedIds] = useState(() =>
158
+ new Set<string>()
159
+ )
160
+
161
+ return <div>{items.length} items</div>
162
+ }
163
+ ```
164
+
165
+ ## 추가 컨텍스트
166
+
167
+ **지연 초기화를 사용해야 하는 경우:**
168
+ - localStorage/sessionStorage에서 데이터 읽기 + JSON 파싱
169
+ - 데이터 구조 구축 (Map, Set, 인덱스)
170
+ - DOM에서 값 읽기
171
+ - 무거운 계산/변환 (정렬, 필터, reduce)
172
+ - 정규식 생성
173
+
174
+ **지연 초기화가 불필요한 경우:**
175
+ - 원시 값: `useState(0)`, `useState('')`
176
+ - 직접 참조: `useState(props.value)`
177
+ - 저렴한 리터럴: `useState({})`, `useState([])`
178
+
179
+ **비동기 초기화:**
180
+ - `useState`는 비동기 함수를 지원하지 않음
181
+ - 비동기 데이터는 null로 초기화 후 useEffect에서 로드
182
+ - 또는 TanStack Query의 `useQuery` 사용
183
+
184
+ **성능 측정:**
185
+ ```tsx
186
+ const [data, setData] = useState(() => {
187
+ const start = performance.now()
188
+ const result = expensiveComputation()
189
+ console.log(`Init took ${performance.now() - start}ms`)
190
+ return result
191
+ })
192
+ ```
193
+
194
+ **참고:** [React useState Lazy Initialization](https://react.dev/reference/react/useState#avoiding-recreating-the-initial-state)
195
+
196
+ 영향도: MEDIUM - 초기화 성능, 렌더링 성능