claudify-agent 0.0.0-stage → 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.
Files changed (48) hide show
  1. package/.claude/QUICK-REFERENCE.md +213 -0
  2. package/.claude/cost-dashboard.md +162 -0
  3. package/.claude/docs/COST-OPTIMIZATION.md +403 -0
  4. package/.claude/docs/MCP-INTEGRATION-GUIDE.md +348 -0
  5. package/.claude/docs/PLAN-MODE-OPTIMIZATION.md +836 -0
  6. package/.claude/hooks/auto-learning-review.ts +195 -0
  7. package/.claude/hooks/auto-lint-fix.ts +104 -0
  8. package/.claude/hooks/auto-security-review.ts +354 -0
  9. package/.claude/hooks/auto-validate.ts +348 -0
  10. package/.claude/hooks/plan-quality-tracker.ts +719 -0
  11. package/.claude/rules/anti-patterns.md +22 -0
  12. package/.claude/rules/context-tier-1.md +41 -0
  13. package/.claude/rules/context-tier-2.md +285 -0
  14. package/.claude/rules/general.md +25 -0
  15. package/.claude/rules/mcp-auto-use.md +46 -0
  16. package/.claude/rules/parallel-exploration-auto.md +31 -0
  17. package/.claude/rules/plan-mode-execution.md +289 -0
  18. package/.claude/rules/plan-mode-research.md +34 -0
  19. package/.claude/rules/plan-mode-structure.md +166 -0
  20. package/.claude/rules/plan-mode-validation.md +130 -0
  21. package/.claude/rules/security-critical.md +19 -0
  22. package/.claude/rules/tool-auto-selection.md +45 -0
  23. package/.claude/rules/tool-strategy.md +22 -0
  24. package/.claude/scripts/auto-validate.js +69 -0
  25. package/.claude/scripts/security-scan.js +45 -0
  26. package/.claude/security-dashboard.md +142 -0
  27. package/.claude/skills/backend-concurrency/SKILL.md +203 -0
  28. package/.claude/skills/debug-optimizer/SKILL.md +399 -0
  29. package/.claude/skills/debug-optimizer.md +12 -0
  30. package/.claude/skills/golang-guide/SKILL.md +177 -0
  31. package/.claude/skills/learning-loop/SKILL.md +308 -0
  32. package/.claude/skills/mcp-mastery/SKILL.md +214 -0
  33. package/.claude/skills/nestjs-guide/SKILL.md +197 -0
  34. package/.claude/skills/nextjs-guide/SKILL.md +687 -0
  35. package/.claude/skills/nextjs.md +13 -0
  36. package/.claude/skills/parallel-exploration/SKILL.md +193 -0
  37. package/.claude/skills/plan-mode-mastery/SKILL.md +263 -0
  38. package/.claude/skills/python-guide/SKILL.md +822 -0
  39. package/.claude/skills/react-guide/SKILL.md +762 -0
  40. package/.claude/skills/react.md +12 -0
  41. package/.claude/skills/security.md +18 -0
  42. package/.claude/skills/solidity-guide/SKILL.md +32 -0
  43. package/.claude/skills/tool-selection/SKILL.md +428 -0
  44. package/.claude/skills/vite-guide/SKILL.md +445 -0
  45. package/CLAUDE.md +49 -0
  46. package/README.md +65 -2
  47. package/bin/cli.js +50 -0
  48. package/package.json +44 -4
@@ -0,0 +1,762 @@
1
+ ---
2
+ name: react-guide
3
+ description: Apply React best practices including modern patterns, hooks, TypeScript, performance optimization, and testing. Use when writing, reviewing, or refactoring React code.
4
+ ---
5
+
6
+ # React Best Practices
7
+
8
+ ## Quick Start
9
+
10
+ When working with React code, follow these core principles:
11
+
12
+ 1. **Modern Patterns**: Use hooks and function components (no class components)
13
+ 2. **TypeScript**: Add proper types, avoid `any`
14
+ 3. **Server Components**: Use RSC for data fetching when possible
15
+ 4. **Performance**: Prevent re-renders, code-split, optimize bundles
16
+ 5. **Testing**: Use React Testing Library with user-behavior queries
17
+ 6. **Accessibility**: Build accessible components by default
18
+
19
+ ## Component Architecture
20
+
21
+ ### Function Components with Hooks
22
+
23
+ ```tsx
24
+ // ✅ Good: Function component with hooks
25
+ interface UserCardProps {
26
+ userId: string;
27
+ showDetails?: boolean;
28
+ }
29
+
30
+ export function UserCard({ userId, showDetails = false }: UserCardProps) {
31
+ const [user, setUser] = useState<User | null>(null);
32
+ const [loading, setLoading] = useState(true);
33
+
34
+ useEffect(() => {
35
+ async function fetchUser() {
36
+ const data = await fetchUserById(userId);
37
+ setUser(data);
38
+ setLoading(false);
39
+ }
40
+ fetchUser();
41
+ }, [userId]);
42
+
43
+ if (loading) return <Spinner />;
44
+ if (!user) return <ErrorMessage />;
45
+
46
+ return (
47
+ <Card>
48
+ <h2>{user.name}</h2>
49
+ {showDetails && <p>{user.email}</p>}
50
+ </Card>
51
+ );
52
+ }
53
+ ```
54
+
55
+ ### Custom Hooks for Reusable Logic
56
+
57
+ ```tsx
58
+ // ✅ Good: Extract stateful logic into custom hooks
59
+ interface UseFetchOptions {
60
+ enabled?: boolean;
61
+ }
62
+
63
+ export function useFetch<T>(
64
+ endpoint: string,
65
+ options: UseFetchOptions = {}
66
+ ) {
67
+ const { enabled = true } = options;
68
+ const [data, setData] = useState<T | null>(null);
69
+ const [loading, setLoading] = useState(false);
70
+ const [error, setError] = useState<Error | null>(null);
71
+
72
+ useEffect(() => {
73
+ if (!enabled) return;
74
+
75
+ const controller = new AbortController();
76
+
77
+ async function fetchData() {
78
+ setLoading(true);
79
+ try {
80
+ const response = await fetch(endpoint, {
81
+ signal: controller.signal,
82
+ });
83
+ const result = await response.json();
84
+ setData(result);
85
+ } catch (err) {
86
+ if (err instanceof Error) setError(err);
87
+ } finally {
88
+ setLoading(false);
89
+ }
90
+ }
91
+
92
+ fetchData();
93
+ return () => controller.abort();
94
+ }, [endpoint, enabled]);
95
+
96
+ return { data, loading, error };
97
+ }
98
+
99
+ // Usage in component
100
+ function UserProfile({ userId }: { userId: string }) {
101
+ const { data: user, loading, error } = useFetch<User>(
102
+ `/api/users/${userId}`
103
+ );
104
+
105
+ if (loading) return <Spinner />;
106
+ if (error) return <ErrorMessage error={error} />;
107
+ if (!user) return <NotFound />;
108
+
109
+ return <div>{user.name}</div>;
110
+ }
111
+ ```
112
+
113
+ ## React Server Components (RSC)
114
+
115
+ ### Server Component Pattern
116
+
117
+ ```tsx
118
+ // ✅ Good: Server Component for data fetching
119
+ import { db } from '@/lib/db';
120
+ import { ProductList } from './ProductList';
121
+
122
+ export default async function ProductsPage() {
123
+ const products = await db.product.findMany();
124
+
125
+ return (
126
+ <div>
127
+ <h1>Products</h1>
128
+ <ProductList products={products} />
129
+ </div>
130
+ );
131
+ }
132
+ ```
133
+
134
+ ### Client Component When Needed
135
+
136
+ ```tsx
137
+ // ✅ Good: Client Component only when interactivity needed
138
+ 'use client';
139
+
140
+ import { useState } from 'react';
141
+
142
+ interface ProductListProps {
143
+ products: Product[];
144
+ }
145
+
146
+ export function ProductList({ products }: ProductListProps) {
147
+ const [filter, setFilter] = useState('');
148
+
149
+ const filteredProducts = products.filter(p =>
150
+ p.name.toLowerCase().includes(filter.toLowerCase())
151
+ );
152
+
153
+ return (
154
+ <div>
155
+ <input
156
+ type="text"
157
+ value={filter}
158
+ onChange={e => setFilter(e.target.value)}
159
+ placeholder="Filter products..."
160
+ aria-label="Filter products"
161
+ />
162
+ <ul>
163
+ {filteredProducts.map(product => (
164
+ <ProductCard key={product.id} product={product} />
165
+ ))}
166
+ </ul>
167
+ </div>
168
+ );
169
+ }
170
+ ```
171
+
172
+ ## Performance Optimization
173
+
174
+ ### Prevent Unnecessary Re-renders
175
+
176
+ ```tsx
177
+ // ✅ Good: React.memo for pure components
178
+ interface ProductCardProps {
179
+ product: Product;
180
+ onAddToCart: (productId: string) => void;
181
+ }
182
+
183
+ export const ProductCard = React.memo(function ProductCard({
184
+ product,
185
+ onAddToCart,
186
+ }: ProductCardProps) {
187
+ return (
188
+ <div>
189
+ <h3>{product.name}</h3>
190
+ <p>${product.price}</p>
191
+ <button onClick={() => onAddToCart(product.id)}>
192
+ Add to Cart
193
+ </button>
194
+ </div>
195
+ );
196
+ });
197
+
198
+ // ✅ Good: useCallback for stable function references
199
+ function ProductList() {
200
+ const [cart, setCart] = useState<Product[]>([]);
201
+
202
+ const addToCart = useCallback((productId: string) => {
203
+ setCart(prev => [...prev, { id: productId }]);
204
+ }, []);
205
+
206
+ return (
207
+ <div>
208
+ {products.map(product => (
209
+ <ProductCard
210
+ key={product.id}
211
+ product={product}
212
+ onAddToCart={addToCart}
213
+ />
214
+ ))}
215
+ </div>
216
+ );
217
+ }
218
+
219
+ // ✅ Good: useMemo for expensive calculations
220
+ function ShoppingCart({ items }: { items: CartItem[] }) {
221
+ const total = useMemo(() => {
222
+ return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
223
+ }, [items]);
224
+
225
+ return <div>Total: ${total}</div>;
226
+ }
227
+ ```
228
+
229
+ ### Code Splitting
230
+
231
+ ```tsx
232
+ // ✅ Good: Lazy loading for route-based splitting
233
+ import { lazy, Suspense } from 'react';
234
+
235
+ const ProductDetails = lazy(() => import('./ProductDetails'));
236
+ const Checkout = lazy(() => import('./Checkout'));
237
+
238
+ function App() {
239
+ return (
240
+ <Suspense fallback={<PageLoader />}>
241
+ <Routes>
242
+ <Route path="/products/:id" element={<ProductDetails />} />
243
+ <Route path="/checkout" element={<Checkout />} />
244
+ </Routes>
245
+ </Suspense>
246
+ );
247
+ }
248
+ ```
249
+
250
+ ## TypeScript Best Practices
251
+
252
+ ### Proper Typing
253
+
254
+ ```tsx
255
+ // ✅ Good: Specific types, no any
256
+ interface ButtonProps {
257
+ variant?: 'primary' | 'secondary' | 'danger';
258
+ size?: 'small' | 'medium' | 'large';
259
+ children: React.ReactNode;
260
+ onClick?: () => void;
261
+ disabled?: boolean;
262
+ ariaLabel?: string;
263
+ }
264
+
265
+ export function Button({
266
+ variant = 'primary',
267
+ size = 'medium',
268
+ children,
269
+ onClick,
270
+ disabled = false,
271
+ ariaLabel,
272
+ }: ButtonProps) {
273
+ return (
274
+ <button
275
+ className={`btn btn-${variant} btn-${size}`}
276
+ onClick={onClick}
277
+ disabled={disabled}
278
+ aria-label={ariaLabel}
279
+ >
280
+ {children}
281
+ </button>
282
+ );
283
+ }
284
+
285
+ // ✅ Good: Type event handlers properly
286
+ interface FormProps {
287
+ onSubmit: (data: FormData) => void;
288
+ }
289
+
290
+ export function Form({ onSubmit }: FormProps) {
291
+ const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
292
+ e.preventDefault();
293
+ const formData = new FormData(e.currentTarget);
294
+ onSubmit({
295
+ email: formData.get('email') as string,
296
+ password: formData.get('password') as string,
297
+ });
298
+ };
299
+
300
+ return (
301
+ <form onSubmit={handleSubmit}>
302
+ <input type="email" name="email" />
303
+ <input type="password" name="password" />
304
+ <button type="submit">Submit</button>
305
+ </form>
306
+ );
307
+ }
308
+ ```
309
+
310
+ ## Testing Patterns
311
+
312
+ ### React Testing Library
313
+
314
+ ```tsx
315
+ // ✅ Good: Test user behavior, not implementation
316
+ import { render, screen, waitFor } from '@testing-library/react';
317
+ import userEvent from '@testing-library/user-event';
318
+ import { UserProfile } from './UserProfile';
319
+
320
+ describe('UserProfile', () => {
321
+ it('displays user data after loading', async () => {
322
+ render(<UserProfile userId="123" />);
323
+
324
+ expect(screen.getByRole('status')).toHaveTextContent('Loading...');
325
+
326
+ await waitFor(() => {
327
+ expect(screen.getByRole('heading', { name: /john doe/i })).toBeInTheDocument();
328
+ });
329
+ });
330
+
331
+ it('allows editing user name', async () => {
332
+ const user = userEvent.setup();
333
+ render(<UserProfile userId="123" />);
334
+
335
+ await waitFor(() => {
336
+ expect(screen.getByRole('heading', { name: /john doe/i })).toBeInTheDocument();
337
+ });
338
+
339
+ const editButton = screen.getByRole('button', { name: /edit/i });
340
+ await user.click(editButton);
341
+
342
+ const nameInput = screen.getByLabelText(/name/i);
343
+ await user.clear(nameInput);
344
+ await user.type(nameInput, 'Jane Doe');
345
+
346
+ const saveButton = screen.getByRole('button', { name: /save/i });
347
+ await user.click(saveButton);
348
+
349
+ await waitFor(() => {
350
+ expect(screen.getByRole('heading', { name: /jane doe/i })).toBeInTheDocument();
351
+ });
352
+ });
353
+
354
+ it('shows error message when fetch fails', async () => {
355
+ server.use(
356
+ rest.get('/api/users/123', (req, res, ctx) => {
357
+ return res(ctx.status(500));
358
+ })
359
+ );
360
+
361
+ render(<UserProfile userId="123" />);
362
+
363
+ await waitFor(() => {
364
+ expect(screen.getByRole('alert')).toHaveTextContent(/error/i);
365
+ });
366
+ });
367
+ });
368
+ ```
369
+
370
+ ### Testing Custom Hooks
371
+
372
+ ```tsx
373
+ // ✅ Good: Test custom hooks in isolation
374
+ import { renderHook, waitFor } from '@testing-library/react';
375
+ import { useFetch } from './useFetch';
376
+
377
+ describe('useFetch', () => {
378
+ it('fetches data successfully', async () => {
379
+ const { result } = renderHook(() => useFetch('/api/users'));
380
+
381
+ expect(result.current.loading).toBe(true);
382
+
383
+ await waitFor(() => {
384
+ expect(result.current.loading).toBe(false);
385
+ });
386
+
387
+ expect(result.current.data).toEqual(mockUsers);
388
+ expect(result.current.error).toBeNull();
389
+ });
390
+
391
+ it('handles fetch error', async () => {
392
+ const { result } = renderHook(() => useFetch('/api/invalid'));
393
+
394
+ await waitFor(() => {
395
+ expect(result.current.loading).toBe(false);
396
+ });
397
+
398
+ expect(result.current.error).toBeInstanceOf(Error);
399
+ expect(result.current.data).toBeNull();
400
+ });
401
+
402
+ it('respects enabled option', () => {
403
+ renderHook(() => useFetch('/api/users', { enabled: false }));
404
+
405
+ expect(fetch).not.toHaveBeenCalled();
406
+ });
407
+ });
408
+ ```
409
+
410
+ ## Accessibility
411
+
412
+ ### Semantic HTML and ARIA
413
+
414
+ ```tsx
415
+ // ✅ Good: Semantic HTML with proper ARIA
416
+ interface ModalProps {
417
+ isOpen: boolean;
418
+ onClose: () => void;
419
+ title: string;
420
+ children: React.ReactNode;
421
+ }
422
+
423
+ export function Modal({ isOpen, onClose, title, children }: ModalProps) {
424
+ useEffect(() => {
425
+ function handleEscape(e: KeyboardEvent) {
426
+ if (e.key === 'Escape') onClose();
427
+ }
428
+
429
+ if (isOpen) {
430
+ document.addEventListener('keydown', handleEscape);
431
+ document.body.style.overflow = 'hidden';
432
+ }
433
+
434
+ return () => {
435
+ document.removeEventListener('keydown', handleEscape);
436
+ document.body.style.overflow = 'unset';
437
+ };
438
+ }, [isOpen, onClose]);
439
+
440
+ if (!isOpen) return null;
441
+
442
+ return (
443
+ <div
444
+ role="dialog"
445
+ aria-modal="true"
446
+ aria-labelledby="modal-title"
447
+ className="modal-overlay"
448
+ onClick={onClose}
449
+ >
450
+ <div className="modal-content" onClick={e => e.stopPropagation()}>
451
+ <header>
452
+ <h2 id="modal-title">{title}</h2>
453
+ <button
454
+ onClick={onClose}
455
+ aria-label="Close modal"
456
+ className="close-button"
457
+ >
458
+ ×
459
+ </button>
460
+ </header>
461
+ <main>{children}</main>
462
+ </div>
463
+ </div>
464
+ );
465
+ }
466
+ ```
467
+
468
+ ### Form Accessibility
469
+
470
+ ```tsx
471
+ // ✅ Good: Accessible form with labels and error messages
472
+ interface InputFieldProps {
473
+ id: string;
474
+ label: string;
475
+ error?: string;
476
+ required?: boolean;
477
+ }
478
+
479
+ export function InputField({
480
+ id,
481
+ label,
482
+ error,
483
+ required = false,
484
+ }: InputFieldProps) {
485
+ return (
486
+ <div className="form-field">
487
+ <label htmlFor={id}>
488
+ {label}
489
+ {required && <span aria-hidden="true"> *</span>}
490
+ </label>
491
+ <input
492
+ id={id}
493
+ name={id}
494
+ aria-required={required}
495
+ aria-invalid={!!error}
496
+ aria-describedby={error ? `${id}-error` : undefined}
497
+ />
498
+ {error && (
499
+ <span id={`${id}-error`} role="alert" className="error-message">
500
+ {error}
501
+ </span>
502
+ )}
503
+ </div>
504
+ );
505
+ }
506
+ ```
507
+
508
+ ## State Management
509
+
510
+ ### Keep State Minimal
511
+
512
+ ```tsx
513
+ // ✅ Good: Minimal state, compute derived values
514
+ interface ShoppingCartProps {
515
+ items: CartItem[];
516
+ }
517
+
518
+ export function ShoppingCart({ items }: ShoppingCartProps) {
519
+ // ✅ Good: Compute derived values during render
520
+ const total = items.reduce((sum, item) => sum + item.price * item.quantity, 0);
521
+ const itemCount = items.reduce((sum, item) => sum + item.quantity, 0);
522
+ const hasItems = items.length > 0;
523
+
524
+ return (
525
+ <div>
526
+ <p>Items: {itemCount}</p>
527
+ <p>Total: ${total}</p>
528
+ {hasItems ? <Checkout /> : <EmptyCart />}
529
+ </div>
530
+ );
531
+ }
532
+ ```
533
+
534
+ ### State Colocation
535
+
536
+ ```tsx
537
+ // ✅ Good: Colocate state to where it's needed
538
+ function ProductList() {
539
+ const [products] = useFetch<Product[]>('/api/products');
540
+
541
+ return (
542
+ <div>
543
+ {products?.map(product => (
544
+ <ProductCard key={product.id} product={product} />
545
+ ))}
546
+ </div>
547
+ );
548
+ }
549
+
550
+ function ProductCard({ product }: { product: Product }) {
551
+ // ✅ Good: State only where needed
552
+ const [isExpanded, setIsExpanded] = useState(false);
553
+
554
+ return (
555
+ <div>
556
+ <h3>{product.name}</h3>
557
+ <p>${product.price}</p>
558
+ {isExpanded && <ProductDetails product={product} />}
559
+ <button onClick={() => setIsExpanded(!isExpanded)}>
560
+ {isExpanded ? 'Show Less' : 'Show More'}
561
+ </button>
562
+ </div>
563
+ );
564
+ }
565
+ ```
566
+
567
+ ## Error Handling
568
+
569
+ ### Error Boundaries
570
+
571
+ ```tsx
572
+ // ✅ Good: Error boundary for graceful failures
573
+ interface ErrorBoundaryState {
574
+ hasError: boolean;
575
+ error?: Error;
576
+ }
577
+
578
+ export class ErrorBoundary extends React.Component<
579
+ { children: React.ReactNode; fallback?: React.ComponentType<{ error?: Error }> },
580
+ ErrorBoundaryState
581
+ > {
582
+ state: ErrorBoundaryState = { hasError: false };
583
+
584
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState {
585
+ return { hasError: true, error };
586
+ }
587
+
588
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
589
+ console.error('Error caught by boundary:', error, errorInfo);
590
+ }
591
+
592
+ render() {
593
+ if (this.state.hasError) {
594
+ const Fallback = this.props.fallback || DefaultErrorFallback;
595
+ return <Fallback error={this.state.error} />;
596
+ }
597
+
598
+ return this.props.children;
599
+ }
600
+ }
601
+
602
+ // Usage
603
+ function App() {
604
+ return (
605
+ <ErrorBoundary fallback={ProductErrorFallback}>
606
+ <ProductList />
607
+ </ErrorBoundary>
608
+ );
609
+ }
610
+ ```
611
+
612
+ ## Project Structure
613
+
614
+ ### Component Organization
615
+
616
+ ```
617
+ src/
618
+ ├── components/
619
+ │ ├── ui/ # Reusable UI components
620
+ │ │ ├── Button.tsx
621
+ │ │ ├── Card.tsx
622
+ │ │ └── Modal.tsx
623
+ │ ├── forms/ # Form components
624
+ │ │ ├── Input.tsx
625
+ │ │ ├── Select.tsx
626
+ │ │ └── Form.tsx
627
+ │ └── layout/ # Layout components
628
+ │ ├── Header.tsx
629
+ │ ├── Footer.tsx
630
+ │ └── Layout.tsx
631
+ ├── hooks/ # Custom hooks
632
+ │ ├── useFetch.ts
633
+ │ ├── useLocalStorage.ts
634
+ │ └── useDebounce.ts
635
+ ├── lib/ # Utilities
636
+ │ ├── api.ts
637
+ │ └── utils.ts
638
+ ├── types/ # TypeScript types
639
+ │ └── index.ts
640
+ └── pages/ # Page components (Next.js)
641
+ ├── index.tsx
642
+ └── products/
643
+ └── [id].tsx
644
+ ```
645
+
646
+ ## Common Pitfalls to Avoid
647
+
648
+ ### ❌ Bad: Effects as Second Rendering System
649
+
650
+ ```tsx
651
+ // ❌ Bad: Computing derived state in effect
652
+ function ShoppingCart({ items }: { items: CartItem[] }) {
653
+ const [total, setTotal] = useState(0);
654
+
655
+ useEffect(() => {
656
+ setTotal(items.reduce((sum, item) => sum + item.price, 0));
657
+ }, [items]);
658
+
659
+ return <div>Total: ${total}</div>;
660
+ }
661
+
662
+ // ✅ Good: Compute during render
663
+ function ShoppingCart({ items }: { items: CartItem[] }) {
664
+ const total = items.reduce((sum, item) => sum + item.price, 0);
665
+ return <div>Total: ${total}</div>;
666
+ }
667
+ ```
668
+
669
+ ### ❌ Bad: Missing Cleanup
670
+
671
+ ```tsx
672
+ // ❌ Bad: Memory leak from unsubscribed event listener
673
+ function WindowTracker() {
674
+ const [width, setWidth] = useState(window.innerWidth);
675
+
676
+ useEffect(() => {
677
+ window.addEventListener('resize', () => {
678
+ setWidth(window.innerWidth);
679
+ });
680
+ }, []);
681
+
682
+ return <div>Window width: {width}</div>;
683
+ }
684
+
685
+ // ✅ Good: Proper cleanup
686
+ function WindowTracker() {
687
+ const [width, setWidth] = useState(window.innerWidth);
688
+
689
+ useEffect(() => {
690
+ function handleResize() {
691
+ setWidth(window.innerWidth);
692
+ }
693
+
694
+ window.addEventListener('resize', handleResize);
695
+ return () => window.removeEventListener('resize', handleResize);
696
+ }, []);
697
+
698
+ return <div>Window width: {width}</div>;
699
+ }
700
+ ```
701
+
702
+ ### ❌ Bad: Array/Object in Dependencies
703
+
704
+ ```tsx
705
+ // ❌ Bad: Object reference changes every render
706
+ function UserProfile({ userId }: { userId: string }) {
707
+ const config = { timeout: 5000, retries: 3 };
708
+
709
+ useEffect(() => {
710
+ fetchUser(userId, config);
711
+ }, [userId, config]); // config changes every render!
712
+
713
+ return <div>...</div>;
714
+ }
715
+
716
+ // ✅ Good: Stable reference or primitive values
717
+ function UserProfile({ userId }: { userId: string }) {
718
+ useEffect(() => {
719
+ const config = { timeout: 5000, retries: 3 };
720
+ fetchUser(userId, config);
721
+ }, [userId]);
722
+
723
+ return <div>...</div>;
724
+ }
725
+ ```
726
+
727
+ ## Commands
728
+
729
+ Run these commands for quality checks:
730
+
731
+ ```bash
732
+ npm run lint # ESLint with React hooks plugin
733
+ npm run typecheck # TypeScript compiler
734
+ npm run test # Jest + React Testing Library
735
+ npm run build # Production build with optimizations
736
+ ```
737
+
738
+ ## Examples
739
+
740
+ ### User Authentication Flow
741
+
742
+ See: `@src/components/auth/LoginForm.tsx` for login pattern
743
+ See: `@src/hooks/useAuth.ts` for authentication hook pattern
744
+ See: `@src/components/auth/ProtectedRoute.tsx` for route protection
745
+
746
+ ### Data Fetching Pattern
747
+
748
+ See: `@src/hooks/useFetch.ts` for generic fetch hook
749
+ See: `@src/components/products/ProductList.tsx` for server component pattern
750
+ See: `@src/lib/api.ts` for API client setup
751
+
752
+ ### Form Handling
753
+
754
+ See: `@src/components/forms/ContactForm.tsx` for controlled form pattern
755
+ See: `@src/components/forms/FormField.tsx` for accessible input pattern
756
+
757
+ ## Additional Resources
758
+
759
+ - [React Documentation](https://react.dev) - Official docs with modern patterns
760
+ - [Vercel React Best Practices](https://vercel.com/blog/introducing-react-best-practices) - Performance framework
761
+ - [React Testing Library](https://testing-library.com/react) - Testing guidelines
762
+ - [WebAIM](https://webaim.org) - Accessibility guidelines