@pageai/ralph-loop 1.0.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/.agent/PROMPT.md +58 -0
- package/.agent/STEERING.md +3 -0
- package/.agent/logs/LOG.md +13 -0
- package/.agent/prd/.gitkeep +0 -0
- package/.agent/screenshots/.gitkeep +0 -0
- package/.agent/skills/component-refactoring/SKILL.md +247 -0
- package/.agent/skills/component-refactoring/references/complexity-patterns.md +485 -0
- package/.agent/skills/component-refactoring/references/component-splitting.md +419 -0
- package/.agent/skills/component-refactoring/references/hook-extraction.md +317 -0
- package/.agent/skills/e2e-tester/SKILL.md +595 -0
- package/.agent/skills/frontend-code-review/SKILL.md +73 -0
- package/.agent/skills/frontend-code-review/references/code-quality.md +28 -0
- package/.agent/skills/frontend-code-review/references/performance.md +36 -0
- package/.agent/skills/frontend-testing/SKILL.md +316 -0
- package/.agent/skills/frontend-testing/assets/component-test.template.tsx +293 -0
- package/.agent/skills/frontend-testing/assets/hook-test.template.ts +207 -0
- package/.agent/skills/frontend-testing/assets/utility-test.template.ts +154 -0
- package/.agent/skills/frontend-testing/references/async-testing.md +345 -0
- package/.agent/skills/frontend-testing/references/checklist.md +188 -0
- package/.agent/skills/frontend-testing/references/common-patterns.md +449 -0
- package/.agent/skills/frontend-testing/references/mocking.md +289 -0
- package/.agent/skills/frontend-testing/references/workflow.md +265 -0
- package/.agent/skills/prd-creator/JSON.md +613 -0
- package/.agent/skills/prd-creator/PRD.md +196 -0
- package/.agent/skills/prd-creator/SKILL.md +143 -0
- package/.agent/skills/skill-creator/SKILL.md +355 -0
- package/.agent/skills/skill-creator/references/output-patterns.md +86 -0
- package/.agent/skills/skill-creator/references/workflows.md +28 -0
- package/.agent/skills/skill-creator/scripts/init_skill.py +300 -0
- package/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
- package/.agent/skills/vercel-react-best-practices/AGENTS.md +2249 -0
- package/.agent/skills/vercel-react-best-practices/SKILL.md +125 -0
- package/.agent/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/.agent/skills/vercel-react-best-practices/rules/advanced-use-latest.md +49 -0
- package/.agent/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
- package/.agent/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
- package/.agent/skills/vercel-react-best-practices/rules/async-dependencies.md +36 -0
- package/.agent/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
- package/.agent/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/.agent/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/.agent/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
- package/.agent/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/.agent/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/.agent/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
- package/.agent/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
- package/.agent/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
- package/.agent/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/.agent/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
- package/.agent/skills/vercel-react-best-practices/rules/server-cache-react.md +26 -0
- package/.agent/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +79 -0
- package/.agent/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
- package/.agent/skills/vitest-best-practices/AGENTS.md +84 -0
- package/.agent/skills/vitest-best-practices/SKILL.md +130 -0
- package/.agent/skills/vitest-best-practices/references/aaa-pattern.md +260 -0
- package/.agent/skills/vitest-best-practices/references/assertions.md +393 -0
- package/.agent/skills/vitest-best-practices/references/async-testing.md +454 -0
- package/.agent/skills/vitest-best-practices/references/error-handling.md +382 -0
- package/.agent/skills/vitest-best-practices/references/organization.md +212 -0
- package/.agent/skills/vitest-best-practices/references/parameterized-tests.md +297 -0
- package/.agent/skills/vitest-best-practices/references/performance.md +528 -0
- package/.agent/skills/vitest-best-practices/references/snapshot-testing.md +483 -0
- package/.agent/skills/vitest-best-practices/references/test-doubles.md +499 -0
- package/.agent/skills/vitest-best-practices/references/vitest-features.md +529 -0
- package/.agent/skills/web-design-guidelines/SKILL.md +39 -0
- package/.agent/tasks/.gitkeep +0 -0
- package/.agent/tasks.json +1 -0
- package/.claude/agents/code-reviewer.md +172 -0
- package/.claude/commands/aw.md +50 -0
- package/.claude/hooks/play-sound.js +87 -0
- package/.claude/hooks/pre-tool-use.js +40 -0
- package/.claude/settings.json +54 -0
- package/.claude/settings.local.json +13 -0
- package/.mcp.json +31 -0
- package/AGENTS.md +44 -0
- package/CLAUDE.md +1 -0
- package/README.md +236 -0
- package/bin/cli.js +156 -0
- package/bin/lib/copy.js +149 -0
- package/bin/lib/display.js +137 -0
- package/package.json +65 -0
- package/ralph.sh +333 -0
- package/scripts/lib/args.sh +44 -0
- package/scripts/lib/cleanup.sh +53 -0
- package/scripts/lib/constants.sh +25 -0
- package/scripts/lib/display.sh +196 -0
- package/scripts/lib/logging.sh +30 -0
- package/scripts/lib/notify.sh +41 -0
- package/scripts/lib/output.sh +147 -0
- package/scripts/lib/preflight.sh +57 -0
- package/scripts/lib/preview.sh +77 -0
- package/scripts/lib/promise.sh +76 -0
- package/scripts/lib/spinner.sh +85 -0
- package/scripts/lib/terminal.sh +57 -0
- package/scripts/lib/timing.sh +223 -0
package/.agent/PROMPT.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
@.agent/tasks.json
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
You are implementing the project described in @.agent/prd/SUMMARY.md
|
|
6
|
+
|
|
7
|
+
Tasks are listed in @.agent/tasks.json
|
|
8
|
+
|
|
9
|
+
## Required Setup
|
|
10
|
+
|
|
11
|
+
Run `npm run dev` (as background process).
|
|
12
|
+
App will be running at http://localhost:6006
|
|
13
|
+
|
|
14
|
+
## Before Starting
|
|
15
|
+
|
|
16
|
+
Check @.agent/STEERING.md for critical work. Complete items in sequence, remove when done. Only proceed to implement tasks if no critical work pending.
|
|
17
|
+
|
|
18
|
+
## Task Flow (ONE TASK ONLY)
|
|
19
|
+
|
|
20
|
+
1. Pick highest-priority task with `passes: false` in `tasks.json`
|
|
21
|
+
2. Read full spec: `.agent/tasks/TASK-${ID}.json`
|
|
22
|
+
3. Check existing dir structure in @.agent/STRUCTURE.md
|
|
23
|
+
4. Implement steps by step according to spec and write unit test
|
|
24
|
+
5. **UI tasks only:** do a Playwright smoke test
|
|
25
|
+
- Check console for errors
|
|
26
|
+
- Write minimal e2e test (happy path only)
|
|
27
|
+
- Skip e2e if unit test already covers functionality
|
|
28
|
+
- Save UI Screenshot to `.agent/screenshots/TASK-${ID}-{index}.png`, verify UI correctness. If debugging, use previous screenshots as reference.
|
|
29
|
+
6. Run `eslint --fix`, `prettier --write` and end to end tests for affected files.
|
|
30
|
+
7. Run `tsc` and unit tests project-wide
|
|
31
|
+
8. All tests must pass. Broke unrelated test? Fix it before proceeding.
|
|
32
|
+
9. When tests pass, set `passes: true` in `tasks.json` for the task you completed.
|
|
33
|
+
10. Log entry → `.agent/logs/LOG.md` (date, brief summary, screenshot path)
|
|
34
|
+
11. Update `.agent/STRUCTURE.md` if dirs changed
|
|
35
|
+
12. Commit changes, using the Conventional Commit format.
|
|
36
|
+
|
|
37
|
+
## Rules
|
|
38
|
+
|
|
39
|
+
- No git init/remote changes. **No git push**.
|
|
40
|
+
- Check the last 5 tasks in `.agent/logs/LOG.md` for past work
|
|
41
|
+
- When ALL tasks pass → output `<promise>COMPLETE</promise>` and **nothing else**.
|
|
42
|
+
|
|
43
|
+
## Help Tags
|
|
44
|
+
|
|
45
|
+
Try solving tasks yourself first.
|
|
46
|
+
Only use when truly stuck.
|
|
47
|
+
|
|
48
|
+
**BLOCKED** — technical issues: Playwright broken, deps won't install, env issues, no network, service outages, invalid credentials. Output:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
<promise>BLOCKED:brief description</promise>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**DECIDE** — need human input: lib choices, architecture, unclear requirements, breaking changes. Output:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
<promise>DECIDE:question (Option A vs B)</promise>
|
|
58
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Project Build Log
|
|
2
|
+
|
|
3
|
+
`Current Status`
|
|
4
|
+
=================
|
|
5
|
+
**Last Updated:** YYYY-MM-DD HH:MM
|
|
6
|
+
**Tasks Completed:** TOTAL_NUMBER_OF_TASKS
|
|
7
|
+
**Current Task:** TASK-CURRENT_TASK_NUMBER Complete
|
|
8
|
+
|
|
9
|
+
----------------------------------------------
|
|
10
|
+
|
|
11
|
+
## Session Log
|
|
12
|
+
|
|
13
|
+
<!-- TODO: Add log entries here -->
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: component-refactoring
|
|
3
|
+
description: Refactor high-complexity React components in frontend. Use when the user asks for code splitting, hook extraction, or complexity reduction, or when you come across a component that is too complex to understand and refactor it.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Component Refactoring Skill
|
|
7
|
+
|
|
8
|
+
Refactor high-complexity React components with the patterns and workflow below.
|
|
9
|
+
|
|
10
|
+
## Core Refactoring Patterns
|
|
11
|
+
|
|
12
|
+
### Pattern 1: Extract Custom Hooks
|
|
13
|
+
|
|
14
|
+
**When**: Component has complex state management, multiple `useState`/`useEffect`, or business logic mixed with UI.
|
|
15
|
+
|
|
16
|
+
**Dify Convention**: Place hooks in a `hooks/` subdirectory or alongside the component as `use-<feature>.ts`.
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
// ❌ Before: Complex state logic in component
|
|
20
|
+
const Configuration: FC = () => {
|
|
21
|
+
const [modelConfig, setModelConfig] = useState<ModelConfig>(...)
|
|
22
|
+
const [datasetConfigs, setDatasetConfigs] = useState<DatasetConfigs>(...)
|
|
23
|
+
const [completionParams, setCompletionParams] = useState<FormValue>({})
|
|
24
|
+
|
|
25
|
+
// 50+ lines of state management logic...
|
|
26
|
+
|
|
27
|
+
return <div>...</div>
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ✅ After: Extract to custom hook
|
|
31
|
+
// hooks/use-model-config.ts
|
|
32
|
+
export const useModelConfig = (appId: string) => {
|
|
33
|
+
const [modelConfig, setModelConfig] = useState<ModelConfig>(...)
|
|
34
|
+
const [completionParams, setCompletionParams] = useState<FormValue>({})
|
|
35
|
+
|
|
36
|
+
// Related state management logic here
|
|
37
|
+
|
|
38
|
+
return { modelConfig, setModelConfig, completionParams, setCompletionParams }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Component becomes cleaner
|
|
42
|
+
const Configuration: FC = () => {
|
|
43
|
+
const { modelConfig, setModelConfig } = useModelConfig(appId)
|
|
44
|
+
return <div>...</div>
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Pattern 2: Extract Sub-Components
|
|
49
|
+
|
|
50
|
+
**When**: Single component has multiple UI sections, conditional rendering blocks, or repeated patterns.
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
// ❌ Before: Monolithic JSX with multiple sections
|
|
54
|
+
const AppInfo = () => {
|
|
55
|
+
return (
|
|
56
|
+
<div>
|
|
57
|
+
{/* 100 lines of header UI */}
|
|
58
|
+
{/* 100 lines of operations UI */}
|
|
59
|
+
{/* 100 lines of modals */}
|
|
60
|
+
</div>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ✅ After: Split into focused components
|
|
65
|
+
// app-info/
|
|
66
|
+
// ├── index.tsx (orchestration only)
|
|
67
|
+
// ├── app-header.tsx (header UI)
|
|
68
|
+
// ├── app-operations.tsx (operations UI)
|
|
69
|
+
// └── app-modals.tsx (modal management)
|
|
70
|
+
|
|
71
|
+
const AppInfo = () => {
|
|
72
|
+
const { showModal, setShowModal } = useAppInfoModals()
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<div>
|
|
76
|
+
<AppHeader appDetail={appDetail} />
|
|
77
|
+
<AppOperations onAction={handleAction} />
|
|
78
|
+
<AppModals show={showModal} onClose={() => setShowModal(null)} />
|
|
79
|
+
</div>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Pattern 3: Simplify Conditional Logic
|
|
85
|
+
|
|
86
|
+
**When**: Deep nesting (> 3 levels), complex ternaries, or multiple `if/else` chains.
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// ❌ Before: Deeply nested conditionals
|
|
90
|
+
const Template = useMemo(() => {
|
|
91
|
+
if (appDetail?.mode === AppModeEnum.CHAT) {
|
|
92
|
+
switch (locale) {
|
|
93
|
+
case LanguagesSupported[1]:
|
|
94
|
+
return <TemplateChatZh />
|
|
95
|
+
case LanguagesSupported[7]:
|
|
96
|
+
return <TemplateChatJa />
|
|
97
|
+
default:
|
|
98
|
+
return <TemplateChatEn />
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (appDetail?.mode === AppModeEnum.ADVANCED_CHAT) {
|
|
102
|
+
// Another 15 lines...
|
|
103
|
+
}
|
|
104
|
+
// More conditions...
|
|
105
|
+
}, [appDetail, locale])
|
|
106
|
+
|
|
107
|
+
// ✅ After: Use lookup tables + early returns
|
|
108
|
+
const TEMPLATE_MAP = {
|
|
109
|
+
[AppModeEnum.CHAT]: {
|
|
110
|
+
[LanguagesSupported[1]]: TemplateChatZh,
|
|
111
|
+
[LanguagesSupported[7]]: TemplateChatJa,
|
|
112
|
+
default: TemplateChatEn,
|
|
113
|
+
},
|
|
114
|
+
[AppModeEnum.ADVANCED_CHAT]: {
|
|
115
|
+
[LanguagesSupported[1]]: TemplateAdvancedChatZh,
|
|
116
|
+
// ...
|
|
117
|
+
},
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const Template = useMemo(() => {
|
|
121
|
+
const modeTemplates = TEMPLATE_MAP[appDetail?.mode]
|
|
122
|
+
if (!modeTemplates) return null
|
|
123
|
+
|
|
124
|
+
const TemplateComponent = modeTemplates[locale] || modeTemplates.default
|
|
125
|
+
return <TemplateComponent appDetail={appDetail} />
|
|
126
|
+
}, [appDetail, locale])
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Pattern 4: Extract API/Data Logic
|
|
130
|
+
|
|
131
|
+
**When**: Component directly handles API calls, data transformation, or complex async operations.
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
// ❌ Before: API logic in component
|
|
135
|
+
const MCPServiceCard = () => {
|
|
136
|
+
const [basicAppConfig, setBasicAppConfig] = useState({})
|
|
137
|
+
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
if (isBasicApp && appId) {
|
|
140
|
+
(async () => {
|
|
141
|
+
const res = await fetchAppDetail({ url: '/apps', id: appId })
|
|
142
|
+
setBasicAppConfig(res?.model_config || {})
|
|
143
|
+
})()
|
|
144
|
+
}
|
|
145
|
+
}, [appId, isBasicApp])
|
|
146
|
+
|
|
147
|
+
// More API-related logic...
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ✅ After: Extract to data hook using React Query
|
|
151
|
+
// use-app-config.ts
|
|
152
|
+
import { useQuery } from '@tanstack/react-query'
|
|
153
|
+
import { get } from '@/service/base'
|
|
154
|
+
|
|
155
|
+
const NAME_SPACE = 'appConfig'
|
|
156
|
+
|
|
157
|
+
export const useAppConfig = (appId: string, isBasicApp: boolean) => {
|
|
158
|
+
return useQuery({
|
|
159
|
+
enabled: isBasicApp && !!appId,
|
|
160
|
+
queryKey: [NAME_SPACE, 'detail', appId],
|
|
161
|
+
queryFn: () => get<AppDetailResponse>(`/apps/${appId}`),
|
|
162
|
+
select: data => data?.model_config || {},
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Component becomes cleaner
|
|
167
|
+
const MCPServiceCard = () => {
|
|
168
|
+
const { data: config, isLoading } = useAppConfig(appId, isBasicApp)
|
|
169
|
+
// UI only
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**React Query Best Practices**:
|
|
174
|
+
- Define `NAME_SPACE` for query key organization
|
|
175
|
+
- Use `enabled` option for conditional fetching
|
|
176
|
+
- Use `select` for data transformation
|
|
177
|
+
- Export invalidation hooks: `useInvalidXxx`
|
|
178
|
+
|
|
179
|
+
### Pattern 5: Extract Modal/Dialog Management
|
|
180
|
+
|
|
181
|
+
**When**: Component manages multiple modals with complex open/close states.
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// ❌ Before: Multiple modal states in component
|
|
185
|
+
const AppInfo = () => {
|
|
186
|
+
const [showEditModal, setShowEditModal] = useState(false)
|
|
187
|
+
const [showDuplicateModal, setShowDuplicateModal] = useState(false)
|
|
188
|
+
const [showConfirmDelete, setShowConfirmDelete] = useState(false)
|
|
189
|
+
const [showSwitchModal, setShowSwitchModal] = useState(false)
|
|
190
|
+
const [showImportDSLModal, setShowImportDSLModal] = useState(false)
|
|
191
|
+
// 5+ more modal states...
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ✅ After: Extract to modal management hook
|
|
195
|
+
type ModalType = 'edit' | 'duplicate' | 'delete' | 'switch' | 'import' | null
|
|
196
|
+
|
|
197
|
+
const useAppInfoModals = () => {
|
|
198
|
+
const [activeModal, setActiveModal] = useState<ModalType>(null)
|
|
199
|
+
|
|
200
|
+
const openModal = useCallback((type: ModalType) => setActiveModal(type), [])
|
|
201
|
+
const closeModal = useCallback(() => setActiveModal(null), [])
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
activeModal,
|
|
205
|
+
openModal,
|
|
206
|
+
closeModal,
|
|
207
|
+
isOpen: (type: ModalType) => activeModal === type,
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Common Mistakes to Avoid
|
|
213
|
+
|
|
214
|
+
### ❌ Over-Engineering
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
// ❌ Too many tiny hooks
|
|
218
|
+
const useButtonText = () => useState('Click')
|
|
219
|
+
const useButtonDisabled = () => useState(false)
|
|
220
|
+
const useButtonLoading = () => useState(false)
|
|
221
|
+
|
|
222
|
+
// ✅ Cohesive hook with related state
|
|
223
|
+
const useButtonState = () => {
|
|
224
|
+
const [text, setText] = useState('Click')
|
|
225
|
+
const [disabled, setDisabled] = useState(false)
|
|
226
|
+
const [loading, setLoading] = useState(false)
|
|
227
|
+
return { text, setText, disabled, setDisabled, loading, setLoading }
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### ❌ Breaking Existing Patterns
|
|
232
|
+
|
|
233
|
+
- Follow existing directory structures
|
|
234
|
+
- Maintain naming conventions
|
|
235
|
+
- Preserve export patterns for compatibility
|
|
236
|
+
|
|
237
|
+
### ❌ Premature Abstraction
|
|
238
|
+
|
|
239
|
+
- Only extract when there's clear complexity benefit
|
|
240
|
+
- Don't create abstractions for single-use code
|
|
241
|
+
- Keep refactored code in the same domain area
|
|
242
|
+
|
|
243
|
+
## References
|
|
244
|
+
|
|
245
|
+
### Related Skills
|
|
246
|
+
|
|
247
|
+
- `frontend-testing` - For testing refactored components
|