devflow-kit 1.1.0 → 1.2.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 (107) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +23 -6
  3. package/dist/plugins.js +67 -3
  4. package/package.json +2 -1
  5. package/plugins/devflow-accessibility/.claude-plugin/plugin.json +15 -0
  6. package/plugins/devflow-ambient/.claude-plugin/plugin.json +1 -1
  7. package/plugins/devflow-ambient/skills/ambient-router/SKILL.md +1 -1
  8. package/plugins/devflow-ambient/skills/ambient-router/references/skill-catalog.md +4 -0
  9. package/plugins/devflow-audit-claude/.claude-plugin/plugin.json +1 -1
  10. package/plugins/devflow-code-review/.claude-plugin/plugin.json +1 -4
  11. package/plugins/devflow-code-review/agents/reviewer.md +8 -0
  12. package/plugins/devflow-code-review/commands/code-review-teams.md +11 -1
  13. package/plugins/devflow-code-review/commands/code-review.md +12 -2
  14. package/plugins/devflow-core-skills/.claude-plugin/plugin.json +2 -6
  15. package/plugins/devflow-debug/.claude-plugin/plugin.json +1 -1
  16. package/plugins/devflow-frontend-design/.claude-plugin/plugin.json +15 -0
  17. package/plugins/devflow-go/.claude-plugin/plugin.json +15 -0
  18. package/plugins/devflow-go/skills/go/SKILL.md +187 -0
  19. package/plugins/devflow-go/skills/go/references/concurrency.md +312 -0
  20. package/plugins/devflow-go/skills/go/references/detection.md +129 -0
  21. package/plugins/devflow-go/skills/go/references/patterns.md +232 -0
  22. package/plugins/devflow-go/skills/go/references/violations.md +205 -0
  23. package/plugins/devflow-implement/.claude-plugin/plugin.json +1 -3
  24. package/plugins/devflow-implement/agents/coder.md +11 -6
  25. package/plugins/devflow-java/.claude-plugin/plugin.json +15 -0
  26. package/plugins/devflow-java/skills/java/SKILL.md +183 -0
  27. package/plugins/devflow-java/skills/java/references/detection.md +120 -0
  28. package/plugins/devflow-java/skills/java/references/modern-java.md +270 -0
  29. package/plugins/devflow-java/skills/java/references/patterns.md +235 -0
  30. package/plugins/devflow-java/skills/java/references/violations.md +213 -0
  31. package/plugins/devflow-python/.claude-plugin/plugin.json +15 -0
  32. package/plugins/devflow-python/skills/python/SKILL.md +188 -0
  33. package/plugins/devflow-python/skills/python/references/async.md +220 -0
  34. package/plugins/devflow-python/skills/python/references/detection.md +128 -0
  35. package/plugins/devflow-python/skills/python/references/patterns.md +226 -0
  36. package/plugins/devflow-python/skills/python/references/violations.md +204 -0
  37. package/plugins/devflow-react/.claude-plugin/plugin.json +15 -0
  38. package/plugins/{devflow-core-skills → devflow-react}/skills/react/SKILL.md +1 -1
  39. package/plugins/{devflow-core-skills → devflow-react}/skills/react/references/patterns.md +3 -3
  40. package/plugins/devflow-resolve/.claude-plugin/plugin.json +1 -1
  41. package/plugins/devflow-rust/.claude-plugin/plugin.json +15 -0
  42. package/plugins/devflow-rust/skills/rust/SKILL.md +193 -0
  43. package/plugins/devflow-rust/skills/rust/references/detection.md +131 -0
  44. package/plugins/devflow-rust/skills/rust/references/ownership.md +242 -0
  45. package/plugins/devflow-rust/skills/rust/references/patterns.md +210 -0
  46. package/plugins/devflow-rust/skills/rust/references/violations.md +191 -0
  47. package/plugins/devflow-self-review/.claude-plugin/plugin.json +1 -1
  48. package/plugins/devflow-specify/.claude-plugin/plugin.json +1 -1
  49. package/plugins/devflow-typescript/.claude-plugin/plugin.json +15 -0
  50. package/plugins/{devflow-core-skills → devflow-typescript}/skills/typescript/references/patterns.md +3 -3
  51. package/shared/agents/coder.md +11 -6
  52. package/shared/agents/reviewer.md +8 -0
  53. package/shared/skills/ambient-router/SKILL.md +1 -1
  54. package/shared/skills/ambient-router/references/skill-catalog.md +4 -0
  55. package/shared/skills/go/SKILL.md +187 -0
  56. package/shared/skills/go/references/concurrency.md +312 -0
  57. package/shared/skills/go/references/detection.md +129 -0
  58. package/shared/skills/go/references/patterns.md +232 -0
  59. package/shared/skills/go/references/violations.md +205 -0
  60. package/shared/skills/java/SKILL.md +183 -0
  61. package/shared/skills/java/references/detection.md +120 -0
  62. package/shared/skills/java/references/modern-java.md +270 -0
  63. package/shared/skills/java/references/patterns.md +235 -0
  64. package/shared/skills/java/references/violations.md +213 -0
  65. package/shared/skills/python/SKILL.md +188 -0
  66. package/shared/skills/python/references/async.md +220 -0
  67. package/shared/skills/python/references/detection.md +128 -0
  68. package/shared/skills/python/references/patterns.md +226 -0
  69. package/shared/skills/python/references/violations.md +204 -0
  70. package/shared/skills/react/SKILL.md +1 -1
  71. package/shared/skills/react/references/patterns.md +3 -3
  72. package/shared/skills/rust/SKILL.md +193 -0
  73. package/shared/skills/rust/references/detection.md +131 -0
  74. package/shared/skills/rust/references/ownership.md +242 -0
  75. package/shared/skills/rust/references/patterns.md +210 -0
  76. package/shared/skills/rust/references/violations.md +191 -0
  77. package/shared/skills/typescript/references/patterns.md +3 -3
  78. package/plugins/devflow-code-review/skills/react/SKILL.md +0 -276
  79. package/plugins/devflow-code-review/skills/react/references/patterns.md +0 -1331
  80. package/plugins/devflow-core-skills/skills/accessibility/SKILL.md +0 -229
  81. package/plugins/devflow-core-skills/skills/accessibility/references/detection.md +0 -171
  82. package/plugins/devflow-core-skills/skills/accessibility/references/patterns.md +0 -670
  83. package/plugins/devflow-core-skills/skills/accessibility/references/violations.md +0 -419
  84. package/plugins/devflow-core-skills/skills/frontend-design/SKILL.md +0 -254
  85. package/plugins/devflow-core-skills/skills/frontend-design/references/detection.md +0 -184
  86. package/plugins/devflow-core-skills/skills/frontend-design/references/patterns.md +0 -511
  87. package/plugins/devflow-core-skills/skills/frontend-design/references/violations.md +0 -453
  88. package/plugins/devflow-core-skills/skills/react/references/violations.md +0 -565
  89. package/plugins/devflow-implement/skills/accessibility/SKILL.md +0 -229
  90. package/plugins/devflow-implement/skills/accessibility/references/detection.md +0 -171
  91. package/plugins/devflow-implement/skills/accessibility/references/patterns.md +0 -670
  92. package/plugins/devflow-implement/skills/accessibility/references/violations.md +0 -419
  93. package/plugins/devflow-implement/skills/frontend-design/SKILL.md +0 -254
  94. package/plugins/devflow-implement/skills/frontend-design/references/detection.md +0 -184
  95. package/plugins/devflow-implement/skills/frontend-design/references/patterns.md +0 -511
  96. package/plugins/devflow-implement/skills/frontend-design/references/violations.md +0 -453
  97. /package/plugins/{devflow-code-review → devflow-accessibility}/skills/accessibility/SKILL.md +0 -0
  98. /package/plugins/{devflow-code-review → devflow-accessibility}/skills/accessibility/references/detection.md +0 -0
  99. /package/plugins/{devflow-code-review → devflow-accessibility}/skills/accessibility/references/patterns.md +0 -0
  100. /package/plugins/{devflow-code-review → devflow-accessibility}/skills/accessibility/references/violations.md +0 -0
  101. /package/plugins/{devflow-code-review → devflow-frontend-design}/skills/frontend-design/SKILL.md +0 -0
  102. /package/plugins/{devflow-code-review → devflow-frontend-design}/skills/frontend-design/references/detection.md +0 -0
  103. /package/plugins/{devflow-code-review → devflow-frontend-design}/skills/frontend-design/references/patterns.md +0 -0
  104. /package/plugins/{devflow-code-review → devflow-frontend-design}/skills/frontend-design/references/violations.md +0 -0
  105. /package/plugins/{devflow-code-review → devflow-react}/skills/react/references/violations.md +0 -0
  106. /package/plugins/{devflow-core-skills → devflow-typescript}/skills/typescript/SKILL.md +0 -0
  107. /package/plugins/{devflow-core-skills → devflow-typescript}/skills/typescript/references/violations.md +0 -0
@@ -0,0 +1,191 @@
1
+ # Rust Violation Examples
2
+
3
+ Extended violation patterns for Rust reviews. Reference from main SKILL.md.
4
+
5
+ ## Unwrap Abuse
6
+
7
+ ### Unwrap in Library Code
8
+
9
+ ```rust
10
+ // VIOLATION: Panics on None — caller has no way to handle failure
11
+ pub fn get_username(users: &HashMap<u64, String>, id: u64) -> &str {
12
+ users.get(&id).unwrap() // Panics if id not found
13
+ }
14
+
15
+ // VIOLATION: Unwrap on parse without context
16
+ let port: u16 = std::env::var("PORT").unwrap().parse().unwrap();
17
+ ```
18
+
19
+ ### Expect Without Useful Message
20
+
21
+ ```rust
22
+ // VIOLATION: Message doesn't help diagnose the problem
23
+ let config = load_config().expect("failed");
24
+
25
+ // CORRECT: Actionable message
26
+ let config = load_config().expect("failed to load config from config.toml — does file exist?");
27
+ ```
28
+
29
+ ---
30
+
31
+ ## Unnecessary Cloning
32
+
33
+ ### Clone to Satisfy Borrow Checker
34
+
35
+ ```rust
36
+ // VIOLATION: Cloning to work around borrow issues
37
+ fn process_items(items: &Vec<Item>) {
38
+ let cloned = items.clone(); // Entire Vec cloned
39
+ for item in &cloned {
40
+ println!("{}", item.name);
41
+ }
42
+ }
43
+
44
+ // CORRECT: Just borrow
45
+ fn process_items(items: &[Item]) {
46
+ for item in items {
47
+ println!("{}", item.name);
48
+ }
49
+ }
50
+ ```
51
+
52
+ ### Clone in Hot Loop
53
+
54
+ ```rust
55
+ // VIOLATION: Allocating on every iteration
56
+ for record in &records {
57
+ let key = record.id.clone(); // String allocation per iteration
58
+ map.insert(key, record);
59
+ }
60
+
61
+ // CORRECT: Borrow or use references
62
+ for record in &records {
63
+ map.insert(&record.id, record);
64
+ }
65
+ ```
66
+
67
+ ---
68
+
69
+ ## Stringly-Typed APIs
70
+
71
+ ### String Where Enum Belongs
72
+
73
+ ```rust
74
+ // VIOLATION: Any typo compiles and fails at runtime
75
+ fn set_status(status: &str) {
76
+ match status {
77
+ "active" => { /* ... */ }
78
+ "inactive" => { /* ... */ }
79
+ _ => panic!("unknown status"), // Runtime failure
80
+ }
81
+ }
82
+
83
+ // CORRECT: Compiler enforces valid values
84
+ enum Status { Active, Inactive }
85
+
86
+ fn set_status(status: Status) {
87
+ match status {
88
+ Status::Active => { /* ... */ }
89
+ Status::Inactive => { /* ... */ }
90
+ } // Exhaustive — no default needed
91
+ }
92
+ ```
93
+
94
+ ---
95
+
96
+ ## Unsafe Without Justification
97
+
98
+ ### Bare Unsafe Block
99
+
100
+ ```rust
101
+ // VIOLATION: No safety comment explaining invariants
102
+ unsafe {
103
+ let ptr = data.as_ptr();
104
+ std::ptr::copy_nonoverlapping(ptr, dest, len);
105
+ }
106
+
107
+ // CORRECT: Document why this is safe
108
+ // SAFETY: `data` is guaranteed to be valid for `len` bytes because
109
+ // it was allocated by `Vec::with_capacity(len)` and filled by `read_exact`.
110
+ // `dest` is a valid pointer from `alloc::alloc(layout)` with matching size.
111
+ unsafe {
112
+ std::ptr::copy_nonoverlapping(data.as_ptr(), dest, len);
113
+ }
114
+ ```
115
+
116
+ ### Unnecessary Unsafe
117
+
118
+ ```rust
119
+ // VIOLATION: Using unsafe when safe alternative exists
120
+ unsafe fn get_element(slice: &[u8], index: usize) -> u8 {
121
+ *slice.get_unchecked(index)
122
+ }
123
+
124
+ // CORRECT: Safe indexing with bounds check
125
+ fn get_element(slice: &[u8], index: usize) -> Option<u8> {
126
+ slice.get(index).copied()
127
+ }
128
+ ```
129
+
130
+ ---
131
+
132
+ ## Ignoring Results
133
+
134
+ ### Discarding Write Errors
135
+
136
+ ```rust
137
+ // VIOLATION: Write failure silently ignored
138
+ let _ = file.write_all(data);
139
+ let _ = file.flush();
140
+
141
+ // CORRECT: Propagate errors
142
+ file.write_all(data)?;
143
+ file.flush()?;
144
+ ```
145
+
146
+ ### Ignoring Lock Poisoning
147
+
148
+ ```rust
149
+ // VIOLATION: Silently ignoring poisoned mutex
150
+ let guard = mutex.lock().unwrap_or_else(|e| e.into_inner());
151
+
152
+ // CORRECT: Handle or propagate the poison
153
+ let guard = mutex.lock().map_err(|_| AppError::LockPoisoned)?;
154
+ ```
155
+
156
+ ---
157
+
158
+ ## Concurrency Violations
159
+
160
+ ### Shared Mutable State Without Synchronization
161
+
162
+ ```rust
163
+ // VIOLATION: Data race potential — no synchronization
164
+ static mut COUNTER: u64 = 0;
165
+
166
+ fn increment() {
167
+ unsafe { COUNTER += 1; } // Undefined behavior under concurrency
168
+ }
169
+
170
+ // CORRECT: Use atomic or mutex
171
+ use std::sync::atomic::{AtomicU64, Ordering};
172
+ static COUNTER: AtomicU64 = AtomicU64::new(0);
173
+
174
+ fn increment() {
175
+ COUNTER.fetch_add(1, Ordering::Relaxed);
176
+ }
177
+ ```
178
+
179
+ ### Blocking in Async Context
180
+
181
+ ```rust
182
+ // VIOLATION: Blocks the async runtime thread
183
+ async fn read_file(path: &str) -> Result<String, io::Error> {
184
+ std::fs::read_to_string(path) // Blocking call in async fn
185
+ }
186
+
187
+ // CORRECT: Use async file I/O or spawn_blocking
188
+ async fn read_file(path: &str) -> Result<String, io::Error> {
189
+ tokio::fs::read_to_string(path).await
190
+ }
191
+ ```
@@ -137,7 +137,7 @@ const isUndefined = (value: unknown): value is undefined =>
137
137
  const isNullish = (value: unknown): value is null | undefined =>
138
138
  value === null || value === undefined;
139
139
 
140
- const isFunction = (value: unknown): value is Function =>
140
+ const isFunction = (value: unknown): value is (...args: unknown[]) => unknown =>
141
141
  typeof value === 'function';
142
142
 
143
143
  const isObject = (value: unknown): value is object =>
@@ -760,7 +760,7 @@ function debounce<T extends (...args: any[]) => any>(
760
760
  fn: T,
761
761
  delayMs: number
762
762
  ): (...args: Parameters<T>) => void {
763
- let timeoutId: NodeJS.Timeout | null = null;
763
+ let timeoutId: ReturnType<typeof setTimeout> | null = null;
764
764
 
765
765
  return (...args: Parameters<T>) => {
766
766
  if (timeoutId) clearTimeout(timeoutId);
@@ -774,7 +774,7 @@ function throttle<T extends (...args: any[]) => any>(
774
774
  limitMs: number
775
775
  ): (...args: Parameters<T>) => void {
776
776
  let lastRun = 0;
777
- let timeoutId: NodeJS.Timeout | null = null;
777
+ let timeoutId: ReturnType<typeof setTimeout> | null = null;
778
778
 
779
779
  return (...args: Parameters<T>) => {
780
780
  const now = Date.now();
@@ -1,276 +0,0 @@
1
- ---
2
- name: react
3
- description: This skill should be used when the user works with React components (.tsx/.jsx), asks about "hooks", "state management", "context providers", "memo optimization", "useEffect", or discusses component composition and rendering performance. Provides patterns for hooks, state, effects, memoization, and React-specific architecture.
4
- user-invocable: false
5
- allowed-tools: Read, Grep, Glob
6
- activation:
7
- file-patterns:
8
- - "**/*.tsx"
9
- - "**/*.jsx"
10
- exclude:
11
- - "node_modules/**"
12
- - "**/*.test.*"
13
- - "**/*.spec.*"
14
- ---
15
-
16
- # React Patterns
17
-
18
- Reference for React-specific patterns, component design, hooks, and performance optimization.
19
-
20
- ## Iron Law
21
-
22
- > **COMPOSITION OVER PROPS**
23
- >
24
- > Use children and compound components, not prop drilling. If a component has >5 props,
25
- > it's doing too much. Split it. If you're passing data through 3+ levels, use context
26
- > or composition. Props are for configuration, not data plumbing.
27
-
28
- ## When This Skill Activates
29
-
30
- - Working with React codebases
31
- - Creating components and hooks
32
- - Managing state and side effects
33
- - Optimizing render performance
34
-
35
- ---
36
-
37
- ## Component Patterns
38
-
39
- ### Functional Component Structure
40
-
41
- ```tsx
42
- export function UserCard({ user, className }: UserCardProps) {
43
- const [isExpanded, setIsExpanded] = useState(false); // 1. Hooks first
44
- const displayName = user.firstName + ' ' + user.lastName; // 2. Derived state
45
- const handleToggle = () => setIsExpanded((prev) => !prev); // 3. Handlers
46
- return ( // 4. Render
47
- <div className={cn('user-card', className)}>
48
- <h3>{displayName}</h3>
49
- {isExpanded && <UserDetails user={user} />}
50
- <button onClick={handleToggle}>{isExpanded ? 'Collapse' : 'Expand'}</button>
51
- </div>
52
- );
53
- }
54
- ```
55
-
56
- ### Composition Over Props
57
-
58
- ```tsx
59
- function Card({ children }: { children: React.ReactNode }) {
60
- return <div className="card">{children}</div>;
61
- }
62
- Card.Header = ({ children }) => <div className="card-header">{children}</div>;
63
- Card.Body = ({ children }) => <div className="card-body">{children}</div>;
64
-
65
- // Usage - flexible, not rigid props
66
- <Card>
67
- <Card.Header><h2>Title</h2></Card.Header>
68
- <Card.Body><p>Content</p></Card.Body>
69
- </Card>
70
- ```
71
-
72
- ---
73
-
74
- ## Hook Patterns
75
-
76
- ```tsx
77
- function useLocalStorage<T>(key: string, initialValue: T) {
78
- const [value, setValue] = useState<T>(() => {
79
- const stored = localStorage.getItem(key);
80
- return stored ? JSON.parse(stored) : initialValue;
81
- });
82
- useEffect(() => localStorage.setItem(key, JSON.stringify(value)), [key, value]);
83
- return [value, setValue] as const;
84
- }
85
- ```
86
-
87
- ---
88
-
89
- ## State Management
90
-
91
- ```tsx
92
- const AuthContext = createContext<AuthContextValue | null>(null);
93
-
94
- export function AuthProvider({ children }: { children: React.ReactNode }) {
95
- const [user, setUser] = useState<User | null>(null);
96
- const login = async (creds: Credentials) => setUser(await authApi.login(creds));
97
- const logout = () => { authApi.logout(); setUser(null); };
98
- return <AuthContext.Provider value={{ user, login, logout }}>{children}</AuthContext.Provider>;
99
- }
100
-
101
- export function useAuth() {
102
- const ctx = useContext(AuthContext);
103
- if (!ctx) throw new Error('useAuth must be used within AuthProvider');
104
- return ctx;
105
- }
106
- ```
107
-
108
- ---
109
-
110
- ## Performance
111
-
112
- ```tsx
113
- function UserList({ users, filter }: { users: User[]; filter: string }) {
114
- const filtered = useMemo(() => users.filter((u) => u.name.includes(filter)), [users, filter]);
115
- const onClick = useCallback(() => console.log('Clicked'), []);
116
- return <ul>{filtered.map((u) => <MemoItem key={u.id} user={u} onClick={onClick} />)}</ul>;
117
- }
118
- const MemoItem = memo(({ user }: { user: User }) => <li>{user.name}</li>);
119
- ```
120
-
121
- ---
122
-
123
- ## Async Parallelization
124
-
125
- ```tsx
126
- // CORRECT: Independent fetches run in parallel
127
- async function loadDashboard(userId: string) {
128
- const [user, orders, preferences] = await Promise.all([
129
- fetchUser(userId),
130
- fetchOrders(userId),
131
- fetchPreferences(userId),
132
- ]);
133
- return { user, orders, preferences };
134
- }
135
-
136
- // VIOLATION: Sequential fetches (3x slower)
137
- async function loadDashboardSlow(userId: string) {
138
- const user = await fetchUser(userId);
139
- const orders = await fetchOrders(userId);
140
- const preferences = await fetchPreferences(userId);
141
- return { user, orders, preferences };
142
- }
143
- ```
144
-
145
- ---
146
-
147
- ## Bundle Size
148
-
149
- ```tsx
150
- // CORRECT: Direct imports (tree-shakable)
151
- import { Button } from '@/components/Button';
152
- import { Card } from '@/components/Card';
153
-
154
- // VIOLATION: Barrel imports (imports entire library)
155
- import { Button, Card } from '@/components';
156
-
157
- // CORRECT: Dynamic import for heavy components
158
- const Chart = lazy(() => import('./Chart'));
159
- const Editor = lazy(() => import('./Editor'));
160
-
161
- function Dashboard() {
162
- return (
163
- <Suspense fallback={<Skeleton />}>
164
- {showChart && <Chart data={data} />}
165
- </Suspense>
166
- );
167
- }
168
- ```
169
-
170
- ---
171
-
172
- ## Re-render Optimization
173
-
174
- ```tsx
175
- // CORRECT: Primitive deps (stable references)
176
- useEffect(() => {
177
- fetchData(userId, isActive);
178
- }, [userId, isActive]); // primitives don't cause unnecessary runs
179
-
180
- // VIOLATION: Object/array deps (new reference every render)
181
- useEffect(() => {
182
- fetchData(options);
183
- }, [options]); // { page: 1 } !== { page: 1 }
184
-
185
- // CORRECT: Stable callback with useCallback
186
- const handleClick = useCallback((id: string) => {
187
- setSelected(id);
188
- }, []); // no deps = stable reference
189
-
190
- // VIOLATION: Inline function (new reference every render)
191
- <List onItemClick={(id) => setSelected(id)} />
192
- ```
193
-
194
- ---
195
-
196
- ## Image Optimization
197
-
198
- ```tsx
199
- // CORRECT: Optimized image with all attributes
200
- <img
201
- src={url}
202
- alt={description}
203
- width={400}
204
- height={300}
205
- loading="lazy"
206
- decoding="async"
207
- style={{ aspectRatio: '4/3' }}
208
- />
209
-
210
- // VIOLATION: Unoptimized image
211
- <img src={url} /> // No dimensions, no lazy loading, layout shift
212
- ```
213
-
214
- ---
215
-
216
- ## Data Structure Performance
217
-
218
- ```tsx
219
- // CORRECT: Set for O(1) membership checks
220
- const selectedIds = new Set(selected);
221
- const isSelected = (id: string) => selectedIds.has(id);
222
-
223
- // VIOLATION: Array.includes is O(n)
224
- const isSelected = (id: string) => selected.includes(id);
225
-
226
- // CORRECT: Map for key-value lookups
227
- const usersById = new Map(users.map(u => [u.id, u]));
228
- const getUser = (id: string) => usersById.get(id);
229
-
230
- // VIOLATION: Array.find is O(n)
231
- const getUser = (id: string) => users.find(u => u.id === id);
232
- ```
233
-
234
- ---
235
-
236
- ## Anti-Patterns
237
-
238
- ```tsx
239
- // BAD: Derived state in useState | GOOD: useMemo
240
- const filtered = useMemo(() => items.filter(i => i.active), [items]);
241
-
242
- // BAD: Missing dependency | GOOD: Include all deps
243
- useEffect(() => { fetchData(userId); }, [userId]);
244
-
245
- // BAD: State update in render | GOOD: Use effect
246
- useEffect(() => { setState(value); }, [value]);
247
- ```
248
-
249
- ---
250
-
251
- ## Extended References
252
-
253
- - `references/patterns.md` - Render props, reducers, virtualization, lazy loading
254
- - `references/hooks.md` - useQuery, useDebouncedValue, usePrevious, useClickOutside
255
- - `references/forms.md` - Controlled forms, validation hooks, multi-step forms
256
- - `references/error-handling.md` - Error boundaries, async error handling
257
-
258
- ---
259
-
260
- ## Checklist
261
-
262
- - [ ] Hooks at top level only
263
- - [ ] All useEffect deps included
264
- - [ ] useCallback for handlers passed to children
265
- - [ ] useMemo for expensive computations
266
- - [ ] Context at appropriate level
267
- - [ ] Error boundaries around risky components
268
- - [ ] Keys on list items (not index)
269
- - [ ] Loading/error states handled
270
- - [ ] Accessibility (aria-*, role)
271
- - [ ] Independent fetches parallelized with Promise.all
272
- - [ ] No barrel imports (direct imports for tree-shaking)
273
- - [ ] Large components lazy-loaded
274
- - [ ] Object/array deps avoided in useEffect (use primitives)
275
- - [ ] Set/Map used for lookups instead of Array.includes/find
276
- - [ ] Images have dimensions, lazy loading, and aspect-ratio