@kood/claude-code 0.4.1 → 0.5.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 +69 -12
- package/package.json +2 -1
- package/templates/.claude/PARALLEL_AGENTS.md +737 -0
- package/templates/.claude/agents/analyst.md +416 -0
- package/templates/.claude/agents/architect.md +569 -0
- package/templates/.claude/agents/code-reviewer.md +132 -133
- package/templates/.claude/agents/dependency-manager.md +93 -94
- package/templates/.claude/agents/deployment-validator.md +64 -65
- package/templates/.claude/agents/designer.md +655 -0
- package/templates/.claude/agents/document-writer.md +500 -0
- package/templates/.claude/agents/explore.md +499 -0
- package/templates/.claude/agents/git-operator.md +74 -75
- package/templates/.claude/agents/implementation-executor.md +138 -109
- package/templates/.claude/agents/ko-to-en-translator.md +18 -22
- package/templates/.claude/agents/lint-fixer.md +250 -93
- package/templates/.claude/agents/planner.md +356 -0
- package/templates/.claude/agents/refactor-advisor.md +135 -136
- package/templates/.claude/commands/bug-fix.md +296 -207
- package/templates/.claude/commands/git-all.md +199 -46
- package/templates/.claude/commands/git-session.md +113 -57
- package/templates/.claude/commands/lint-fix.md +219 -153
- package/templates/.claude/commands/lint-init.md +113 -76
- package/templates/.claude/commands/pre-deploy.md +190 -124
- package/templates/.claude/commands/refactor.md +407 -162
- package/templates/.claude/commands/version-update.md +138 -37
- package/templates/.claude/instructions/context-engineering/ANTHROPIC_CONTEXT_ENGINEERING.md +178 -0
- package/templates/.claude/instructions/context-engineering/references/claude-4x.md +215 -0
- package/templates/.claude/instructions/context-engineering/references/core-principles.md +137 -0
- package/templates/.claude/instructions/context-engineering/references/examples.md +351 -0
- package/templates/.claude/instructions/context-engineering/references/techniques.md +162 -0
- package/templates/.claude/instructions/parallel-agent-execution.md +874 -0
- package/templates/.claude/skills/docs-creator/AGENTS.md +238 -0
- package/templates/.claude/{commands/docs-creator.md → skills/docs-creator/SKILL.md} +61 -75
- package/templates/.claude/skills/docs-refactor/AGENTS.md +270 -0
- package/templates/.claude/{commands/docs-refactor.md → skills/docs-refactor/SKILL.md} +30 -44
- package/templates/.claude/skills/execute/SKILL.md +451 -0
- package/templates/.claude/skills/figma-to-code/AGENTS.md +287 -0
- package/templates/.claude/skills/figma-to-code/SKILL.md +225 -225
- package/templates/.claude/skills/figma-to-code/references/design-tokens.md +75 -73
- package/templates/.claude/skills/figma-to-code/references/figma-mcp-tools.md +73 -73
- package/templates/.claude/skills/figma-to-code/references/layout-mapping.md +104 -104
- package/templates/.claude/skills/figma-to-code/references/responsive-design.md +99 -99
- package/templates/.claude/skills/figma-to-code/references/verification.md +91 -91
- package/templates/.claude/skills/global-uiux-design/AGENTS.md +317 -0
- package/templates/.claude/skills/global-uiux-design/SKILL.md +738 -0
- package/templates/.claude/skills/global-uiux-design/references/accessibility.md +401 -0
- package/templates/.claude/skills/global-uiux-design/references/color-system.md +275 -0
- package/templates/.claude/skills/global-uiux-design/references/design-philosophy.md +206 -0
- package/templates/.claude/skills/global-uiux-design/references/design-systems.md +446 -0
- package/templates/.claude/skills/korea-uiux-design/AGENTS.md +307 -0
- package/templates/.claude/skills/korea-uiux-design/SKILL.md +170 -0
- package/templates/.claude/skills/nextjs-react-best-practices/AGENTS.md +95 -116
- package/templates/.claude/skills/nextjs-react-best-practices/SKILL.md +134 -152
- package/templates/.claude/skills/nextjs-react-best-practices/rules/advanced-event-handler-refs.md +6 -6
- package/templates/.claude/skills/nextjs-react-best-practices/rules/advanced-use-latest.md +5 -5
- package/templates/.claude/skills/nextjs-react-best-practices/rules/async-api-routes.md +5 -5
- package/templates/.claude/skills/nextjs-react-best-practices/rules/async-defer-await.md +22 -22
- package/templates/.claude/skills/nextjs-react-best-practices/rules/async-dependencies.md +5 -5
- package/templates/.claude/skills/nextjs-react-best-practices/rules/async-parallel.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/async-suspense-boundaries.md +21 -21
- package/templates/.claude/skills/nextjs-react-best-practices/rules/bundle-barrel-imports.md +18 -18
- package/templates/.claude/skills/nextjs-react-best-practices/rules/bundle-conditional.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/bundle-defer-third-party.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/bundle-dynamic-imports.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/bundle-preload.md +5 -5
- package/templates/.claude/skills/nextjs-react-best-practices/rules/client-event-listeners.md +9 -9
- package/templates/.claude/skills/nextjs-react-best-practices/rules/client-swr-dedup.md +7 -7
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-batch-dom-css.md +13 -13
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-cache-function-results.md +14 -14
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-cache-property-access.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-cache-storage.md +10 -10
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-combine-iterations.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-early-exit.md +7 -7
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-hoist-regexp.md +6 -6
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-index-maps.md +6 -6
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-length-check-first.md +14 -14
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-min-max-loop.md +16 -16
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-set-map-lookups.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-tosorted-immutable.md +17 -17
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rendering-activity.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rendering-animate-svg-wrapper.md +11 -11
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rendering-conditional-render.md +8 -8
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rendering-content-visibility.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rendering-hoist-jsx.md +6 -6
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rendering-hydration-no-flicker.md +14 -14
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rendering-svg-precision.md +5 -5
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rerender-defer-reads.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rerender-dependencies.md +7 -7
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rerender-derived-state.md +5 -5
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rerender-functional-setstate.md +34 -34
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rerender-lazy-state-init.md +15 -15
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rerender-memo.md +5 -5
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rerender-transitions.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/server-after-nonblocking.md +24 -24
- package/templates/.claude/skills/nextjs-react-best-practices/rules/server-cache-lru.md +10 -10
- package/templates/.claude/skills/nextjs-react-best-practices/rules/server-cache-react.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/server-parallel-fetching.md +5 -5
- package/templates/.claude/skills/nextjs-react-best-practices/rules/server-serialization.md +6 -6
- package/templates/.claude/skills/plan/SKILL.md +594 -0
- package/templates/.claude/skills/prd/SKILL.md +496 -0
- package/templates/.claude/skills/ralph/AGENTS.md +393 -0
- package/templates/.claude/skills/ralph/SKILL.md +1035 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/AGENTS.md +100 -121
- package/templates/.claude/skills/tanstack-start-react-best-practices/SKILL.md +139 -157
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-defer-await.md +22 -22
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-dependencies.md +5 -5
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-loader.md +7 -7
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-parallel.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-barrel-imports.md +18 -18
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-conditional.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-defer-third-party.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-lazy-routes.md +12 -12
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-preload.md +5 -5
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-event-listeners.md +9 -9
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-tanstack-query.md +12 -12
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-batch-dom-css.md +13 -13
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-cache-function-results.md +14 -14
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-cache-property-access.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-cache-storage.md +10 -10
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-combine-iterations.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-early-exit.md +7 -7
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-hoist-regexp.md +6 -6
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-index-maps.md +6 -6
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-length-check-first.md +14 -14
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-min-max-loop.md +16 -16
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-set-map-lookups.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-tosorted-immutable.md +17 -17
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-animate-svg-wrapper.md +11 -11
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-conditional-render.md +8 -8
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-content-visibility.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-hoist-jsx.md +6 -6
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-svg-precision.md +5 -5
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-defer-reads.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-dependencies.md +7 -7
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-derived-state.md +5 -5
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-functional-setstate.md +34 -34
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-lazy-state-init.md +15 -15
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-memo.md +5 -5
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-transitions.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-cache-lru.md +12 -12
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-deferred-data.md +14 -14
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-parallel-fetching.md +9 -9
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-serialization.md +6 -6
- package/templates/.claude/commands/agent-creator.md +0 -370
- package/templates/.claude/commands/command-creator.md +0 -524
- package/templates/.claude/commands/execute.md +0 -469
- package/templates/.claude/commands/git.md +0 -98
- package/templates/.claude/commands/plan.md +0 -526
- package/templates/.claude/commands/prd.md +0 -629
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-derived-state.md
CHANGED
|
@@ -5,21 +5,21 @@ impactDescription: reduces re-render frequency
|
|
|
5
5
|
tags: rerender, derived-state, media-query, optimization
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 파생 상태 구독
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
리렌더링 빈도를 줄이기 위해 연속적인 값 대신 파생된 boolean 상태를 구독하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**잘못된 예시 (픽셀 변경마다 리렌더링):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
function Sidebar() {
|
|
16
|
-
const width = useWindowWidth() //
|
|
16
|
+
const width = useWindowWidth() // 연속적으로 업데이트됨
|
|
17
17
|
const isMobile = width < 768
|
|
18
18
|
return <nav className={isMobile ? 'mobile' : 'desktop'}>
|
|
19
19
|
}
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
**올바른 예시 (boolean 변경 시에만 리렌더링):**
|
|
23
23
|
|
|
24
24
|
```tsx
|
|
25
25
|
function Sidebar() {
|
|
@@ -5,70 +5,70 @@ impactDescription: prevents stale closures and unnecessary callback recreations
|
|
|
5
5
|
tags: react, hooks, useState, useCallback, callbacks, closures
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 함수형 setState 업데이트 사용
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
현재 상태 값을 기반으로 상태를 업데이트할 때는 상태 변수를 직접 참조하는 대신 setState의 함수형 업데이트 형태를 사용하세요. 이를 통해 stale closure를 방지하고, 불필요한 의존성을 제거하며, 안정적인 콜백 참조를 생성할 수 있습니다.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**잘못된 예시 (상태를 의존성으로 필요):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
function TodoList() {
|
|
16
16
|
const [items, setItems] = useState(initialItems)
|
|
17
|
-
|
|
18
|
-
//
|
|
17
|
+
|
|
18
|
+
// 콜백은 items에 의존해야 하며, items 변경마다 재생성됨
|
|
19
19
|
const addItems = useCallback((newItems: Item[]) => {
|
|
20
20
|
setItems([...items, ...newItems])
|
|
21
|
-
}, [items]) // ❌ items
|
|
22
|
-
|
|
23
|
-
//
|
|
21
|
+
}, [items]) // ❌ items 의존성으로 인한 재생성
|
|
22
|
+
|
|
23
|
+
// 의존성을 잊으면 stale closure 위험
|
|
24
24
|
const removeItem = useCallback((id: string) => {
|
|
25
25
|
setItems(items.filter(item => item.id !== id))
|
|
26
|
-
}, []) // ❌
|
|
27
|
-
|
|
26
|
+
}, []) // ❌ items 의존성 누락 - stale items 사용!
|
|
27
|
+
|
|
28
28
|
return <ItemsEditor items={items} onAdd={addItems} onRemove={removeItem} />
|
|
29
29
|
}
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
첫 번째 콜백은 `items`가 변경될 때마다 재생성되어 자식 컴포넌트가 불필요하게 리렌더링될 수 있습니다. 두 번째 콜백은 stale closure 버그가 있어 항상 초기 `items` 값을 참조합니다.
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
**올바른 예시 (안정적인 콜백, stale closure 없음):**
|
|
35
35
|
|
|
36
36
|
```tsx
|
|
37
37
|
function TodoList() {
|
|
38
38
|
const [items, setItems] = useState(initialItems)
|
|
39
|
-
|
|
40
|
-
//
|
|
39
|
+
|
|
40
|
+
// 안정적인 콜백, 재생성 안 됨
|
|
41
41
|
const addItems = useCallback((newItems: Item[]) => {
|
|
42
42
|
setItems(curr => [...curr, ...newItems])
|
|
43
|
-
}, []) // ✅
|
|
44
|
-
|
|
45
|
-
//
|
|
43
|
+
}, []) // ✅ 의존성 불필요
|
|
44
|
+
|
|
45
|
+
// 항상 최신 상태 사용, stale closure 위험 없음
|
|
46
46
|
const removeItem = useCallback((id: string) => {
|
|
47
47
|
setItems(curr => curr.filter(item => item.id !== id))
|
|
48
|
-
}, []) // ✅
|
|
49
|
-
|
|
48
|
+
}, []) // ✅ 안전하고 안정적
|
|
49
|
+
|
|
50
50
|
return <ItemsEditor items={items} onAdd={addItems} onRemove={removeItem} />
|
|
51
51
|
}
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
**장점:**
|
|
55
55
|
|
|
56
|
-
1.
|
|
57
|
-
2. **
|
|
58
|
-
3.
|
|
59
|
-
4.
|
|
56
|
+
1. **안정적인 콜백 참조** - 상태 변경 시 콜백을 재생성할 필요 없음
|
|
57
|
+
2. **Stale closure 없음** - 항상 최신 상태 값으로 동작
|
|
58
|
+
3. **적은 의존성** - 의존성 배열을 단순화하고 메모리 누수 감소
|
|
59
|
+
4. **버그 방지** - React closure 버그의 가장 흔한 원인 제거
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
**함수형 업데이트를 사용해야 하는 경우:**
|
|
62
62
|
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
63
|
+
- 현재 상태 값에 의존하는 모든 setState
|
|
64
|
+
- 상태가 필요한 useCallback/useMemo 내부
|
|
65
|
+
- 상태를 참조하는 이벤트 핸들러
|
|
66
|
+
- 상태를 업데이트하는 비동기 작업
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
**직접 업데이트를 사용해도 되는 경우:**
|
|
69
69
|
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
-
-
|
|
70
|
+
- 정적 값으로 상태 설정: `setCount(0)`
|
|
71
|
+
- props/arguments로만 상태 설정: `setName(newName)`
|
|
72
|
+
- 상태가 이전 값에 의존하지 않는 경우
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
**참고:** 프로젝트에 [React Compiler](https://react.dev/learn/react-compiler)가 활성화되어 있다면 컴파일러가 일부 경우를 자동으로 최적화할 수 있지만, 정확성과 stale closure 버그 방지를 위해 함수형 업데이트는 여전히 권장됩니다.
|
|
@@ -5,54 +5,54 @@ impactDescription: wasted computation on every render
|
|
|
5
5
|
tags: react, hooks, useState, performance, initialization
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 지연 상태 초기화 사용
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
비용이 큰 초기 값에는 `useState`에 함수를 전달하세요. 함수 형태를 사용하지 않으면 초기화 값이 한 번만 사용되지만 매 렌더링마다 실행됩니다.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**잘못된 예시 (매 렌더링마다 실행):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
function FilteredList({ items }: { items: Item[] }) {
|
|
16
|
-
// buildSearchIndex()
|
|
16
|
+
// buildSearchIndex()가 초기화 후에도 매 렌더링마다 실행됨
|
|
17
17
|
const [searchIndex, setSearchIndex] = useState(buildSearchIndex(items))
|
|
18
18
|
const [query, setQuery] = useState('')
|
|
19
|
-
|
|
20
|
-
//
|
|
19
|
+
|
|
20
|
+
// query가 변경되면 buildSearchIndex가 불필요하게 다시 실행됨
|
|
21
21
|
return <SearchResults index={searchIndex} query={query} />
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
function UserProfile() {
|
|
25
|
-
// JSON.parse
|
|
25
|
+
// JSON.parse가 매 렌더링마다 실행됨
|
|
26
26
|
const [settings, setSettings] = useState(
|
|
27
27
|
JSON.parse(localStorage.getItem('settings') || '{}')
|
|
28
28
|
)
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
return <SettingsForm settings={settings} onChange={setSettings} />
|
|
31
31
|
}
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
**올바른 예시 (한 번만 실행):**
|
|
35
35
|
|
|
36
36
|
```tsx
|
|
37
37
|
function FilteredList({ items }: { items: Item[] }) {
|
|
38
|
-
// buildSearchIndex()
|
|
38
|
+
// buildSearchIndex()가 초기 렌더링 시에만 실행됨
|
|
39
39
|
const [searchIndex, setSearchIndex] = useState(() => buildSearchIndex(items))
|
|
40
40
|
const [query, setQuery] = useState('')
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
return <SearchResults index={searchIndex} query={query} />
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
function UserProfile() {
|
|
46
|
-
// JSON.parse
|
|
46
|
+
// JSON.parse가 초기 렌더링 시에만 실행됨
|
|
47
47
|
const [settings, setSettings] = useState(() => {
|
|
48
48
|
const stored = localStorage.getItem('settings')
|
|
49
49
|
return stored ? JSON.parse(stored) : {}
|
|
50
50
|
})
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
return <SettingsForm settings={settings} onChange={setSettings} />
|
|
53
53
|
}
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
localStorage/sessionStorage에서 초기 값을 계산하거나, 데이터 구조(인덱스, 맵)를 구축하거나, DOM에서 읽거나, 무거운 변환을 수행할 때 지연 초기화를 사용하세요.
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
단순한 원시 값(`useState(0)`), 직접 참조(`useState(props.value)`), 저렴한 리터럴(`useState({})`)의 경우 함수 형태는 불필요합니다.
|
|
@@ -5,11 +5,11 @@ impactDescription: enables early returns
|
|
|
5
5
|
tags: rerender, memo, useMemo, optimization
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 메모이제이션된 컴포넌트로 추출
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
비용이 큰 작업을 메모이제이션된 컴포넌트로 추출하여 계산 전에 조기 반환을 활성화하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**잘못된 예시 (로딩 중에도 avatar 계산):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
function Profile({ user, loading }: Props) {
|
|
@@ -23,7 +23,7 @@ function Profile({ user, loading }: Props) {
|
|
|
23
23
|
}
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
**올바른 예시 (로딩 중에는 계산 생략):**
|
|
27
27
|
|
|
28
28
|
```tsx
|
|
29
29
|
const UserAvatar = memo(function UserAvatar({ user }: { user: User }) {
|
|
@@ -41,4 +41,4 @@ function Profile({ user, loading }: Props) {
|
|
|
41
41
|
}
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
**참고:** 프로젝트에 [React Compiler](https://react.dev/learn/react-compiler)가 활성화되어 있다면, `memo()`와 `useMemo()`를 사용한 수동 메모이제이션은 필요하지 않습니다. 컴파일러가 자동으로 리렌더링을 최적화합니다.
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-transitions.md
CHANGED
|
@@ -5,11 +5,11 @@ impactDescription: maintains UI responsiveness
|
|
|
5
5
|
tags: rerender, transitions, startTransition, performance
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 긴급하지 않은 업데이트에 Transitions 사용
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
빈번하고 긴급하지 않은 상태 업데이트를 transitions로 표시하여 UI 응답성을 유지하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**잘못된 예시 (스크롤마다 UI 차단):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
function ScrollTracker() {
|
|
@@ -22,7 +22,7 @@ function ScrollTracker() {
|
|
|
22
22
|
}
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
**올바른 예시 (논블로킹 업데이트):**
|
|
26
26
|
|
|
27
27
|
```tsx
|
|
28
28
|
import { startTransition } from 'react'
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-cache-lru.md
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
2
|
+
title: 크로스 리퀘스트 LRU 캐싱
|
|
3
3
|
impact: HIGH
|
|
4
|
-
impactDescription:
|
|
4
|
+
impactDescription: 요청 간 캐싱
|
|
5
5
|
tags: server, cache, lru, cross-request
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 크로스 리퀘스트 LRU 캐싱
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
순차적 요청 간 공유되는 데이터 (사용자가 버튼 A 클릭 후 버튼 B 클릭)에는 LRU 캐시 사용.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**구현:**
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
import { LRUCache } from 'lru-cache'
|
|
16
16
|
|
|
17
17
|
const cache = new LRUCache<string, any>({
|
|
18
18
|
max: 1000,
|
|
19
|
-
ttl: 5 * 60 * 1000 // 5
|
|
19
|
+
ttl: 5 * 60 * 1000 // 5분
|
|
20
20
|
})
|
|
21
21
|
|
|
22
22
|
export async function getUser(id: string) {
|
|
@@ -28,14 +28,14 @@ export async function getUser(id: string) {
|
|
|
28
28
|
return user
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
//
|
|
32
|
-
//
|
|
31
|
+
// 요청 1: DB 쿼리, 결과 캐싱
|
|
32
|
+
// 요청 2: 캐시 히트, DB 쿼리 없음
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
순차적 사용자 액션이 수초 내에 동일한 데이터가 필요한 여러 엔드포인트를 호출할 때 사용.
|
|
36
36
|
|
|
37
|
-
**
|
|
37
|
+
**Vercel의 [Fluid Compute](https://vercel.com/docs/fluid-compute)에서:** LRU 캐싱이 특히 효과적. 여러 동시 요청이 동일한 함수 인스턴스와 캐시를 공유할 수 있습니다. 즉, Redis 같은 외부 스토리지 없이 요청 간 캐시가 유지됩니다.
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
**기존 서버리스 환경:** 각 호출이 격리되어 실행되므로 프로세스 간 캐싱을 위해 Redis 고려.
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
참고: [https://github.com/isaacs/node-lru-cache](https://github.com/isaacs/node-lru-cache)
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-deferred-data.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
2
|
+
title: 중요하지 않은 콘텐츠에 지연 데이터 사용
|
|
3
3
|
impact: HIGH
|
|
4
|
-
impactDescription:
|
|
4
|
+
impactDescription: 초기 페이지 렌더링 속도 향상
|
|
5
5
|
tags: server, streaming, suspense, deferred-data, ux
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 중요하지 않은 콘텐츠에 지연 데이터 (Deferred Data) 사용
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
중요한 데이터는 `await`로 로드하고, 중요하지 않은 데이터는 Promise로 반환해 스트리밍. 느린 쿼리가 백그라운드에서 완료되는 동안 페이지를 즉시 렌더링합니다.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**❌ 잘못된 예 (느린 쿼리에서 차단):**
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
import { createFileRoute } from '@tanstack/react-router'
|
|
@@ -17,15 +17,15 @@ import { getPost, getComments } from '@/functions/data'
|
|
|
17
17
|
|
|
18
18
|
export const Route = createFileRoute('/posts/$postId')({
|
|
19
19
|
loader: async ({ params }) => {
|
|
20
|
-
const post = await getPost(params.postId) //
|
|
21
|
-
const comments = await getComments(params.postId) //
|
|
20
|
+
const post = await getPost(params.postId) // 빠름: 50ms
|
|
21
|
+
const comments = await getComments(params.postId) // 느림: 3s
|
|
22
22
|
return { post, comments }
|
|
23
23
|
}
|
|
24
24
|
})
|
|
25
|
-
//
|
|
25
|
+
// 총 대기 시간: 3.05초 후 페이지 렌더링
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
**✅ 올바른 예 (느린 데이터 스트리밍):**
|
|
29
29
|
|
|
30
30
|
```typescript
|
|
31
31
|
import { createFileRoute, Await } from '@tanstack/react-router'
|
|
@@ -34,10 +34,10 @@ import { Suspense } from 'react'
|
|
|
34
34
|
|
|
35
35
|
export const Route = createFileRoute('/posts/$postId')({
|
|
36
36
|
loader: async ({ params }) => {
|
|
37
|
-
//
|
|
37
|
+
// 중요: 즉시 await
|
|
38
38
|
const post = await getPost(params.postId)
|
|
39
39
|
|
|
40
|
-
//
|
|
40
|
+
// 중요하지 않음: Promise 반환 (await 하지 않음)
|
|
41
41
|
const deferredComments = getComments(params.postId)
|
|
42
42
|
|
|
43
43
|
return { post, deferredComments }
|
|
@@ -50,7 +50,7 @@ function PostPage() {
|
|
|
50
50
|
|
|
51
51
|
return (
|
|
52
52
|
<div>
|
|
53
|
-
<PostContent post={post} /> {/*
|
|
53
|
+
<PostContent post={post} /> {/* 즉시 렌더링 */}
|
|
54
54
|
|
|
55
55
|
<Suspense fallback={<CommentsSkeleton />}>
|
|
56
56
|
<Await promise={deferredComments}>
|
|
@@ -62,6 +62,6 @@ function PostPage() {
|
|
|
62
62
|
}
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
페이지가 3초 대신 50ms에 렌더링됩니다. 댓글은 준비되면 스트리밍. 다음에 사용: 분석, 추천, 사용자 활동, 소셜 기능.
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
참고: [TanStack Router Deferred Data Loading](https://tanstack.com/router/v1/docs/framework/react/guide/deferred-data-loading)
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
2
|
+
title: 병렬 서버 함수 호출을 위한 컴포넌트 구조 재조정
|
|
3
3
|
impact: HIGH
|
|
4
|
-
impactDescription:
|
|
4
|
+
impactDescription: 컴포넌트 레벨 워터폴 제거
|
|
5
5
|
tags: server, parallelization, architecture, server-functions
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 병렬 서버 함수 호출을 위한 컴포넌트 구조 재조정
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
순차적 서버 함수 호출을 강제하는 중첩 컴포넌트 구조 방지. 가능하면 부모 loader로 데이터 페칭 이동.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**❌ 잘못된 예 (순차 실행: User → Posts → Comments):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
// routes/dashboard.tsx
|
|
@@ -25,17 +25,17 @@ function Dashboard() {
|
|
|
25
25
|
|
|
26
26
|
// components/UserPosts.tsx
|
|
27
27
|
function UserPosts({ userId }) {
|
|
28
|
-
const posts = await getPosts(userId) //
|
|
28
|
+
const posts = await getPosts(userId) // 로드될 때까지 차단
|
|
29
29
|
return posts.map(p => <PostComments postId={p.id} />)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
function PostComments({ postId }) {
|
|
33
|
-
const comments = await getComments(postId) //
|
|
33
|
+
const comments = await getComments(postId) // 순차 워터폴
|
|
34
34
|
return <CommentList comments={comments} />
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
**✅ 올바른 예 (loader에서 병렬 페칭):**
|
|
39
39
|
|
|
40
40
|
```tsx
|
|
41
41
|
// routes/dashboard.tsx
|
|
@@ -57,4 +57,4 @@ function Dashboard() {
|
|
|
57
57
|
}
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
loader에서 데이터 페칭을 중앙화하면 워터폴을 줄이고 병렬 실행이 가능합니다.
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-serialization.md
CHANGED
|
@@ -5,25 +5,25 @@ impactDescription: reduces data transfer size
|
|
|
5
5
|
tags: server, rsc, serialization, props
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## RSC 경계에서 직렬화 최소화
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
React Server/Client 경계는 모든 객체 속성을 문자열로 직렬화하여 HTML 응답 및 후속 RSC 요청에 포함합니다. 이 직렬화된 데이터는 페이지 가중치와 로드 시간에 직접 영향을 미치므로 **크기가 매우 중요합니다**. 클라이언트가 실제로 사용하는 필드만 전달하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**❌ 잘못된 예시 (50개 필드 모두 직렬화):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
async function Page() {
|
|
16
|
-
const user = await fetchUser() // 50
|
|
16
|
+
const user = await fetchUser() // 50개 필드
|
|
17
17
|
return <Profile user={user} />
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
'use client'
|
|
21
21
|
function Profile({ user }: { user: User }) {
|
|
22
|
-
return <div>{user.name}</div> //
|
|
22
|
+
return <div>{user.name}</div> // 1개 필드만 사용
|
|
23
23
|
}
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
**✅ 올바른 예시 (1개 필드만 직렬화):**
|
|
27
27
|
|
|
28
28
|
```tsx
|
|
29
29
|
async function Page() {
|