| name | developing-with-react |
| description | React 18+ development with hooks, state management, component patterns, and Next.js integration. Use when building React applications or working with JSX/TSX components. |
React Framework - Quick Reference
Version: 1.0.0 | Framework: React 18+ | Use Case: Fast lookups during active development
When to Use
Load this skill when:
package.jsoncontains"react"dependency (>=18.0.0)- Project has
.jsxor.tsxfiles insrc/ - Next.js, Vite, or Create React App detected
- User mentions "React" in task description
Minimum Detection Confidence: 0.8 (80%)
Quick Start
import { FC, useState } from 'react';
interface Props {
title: string;
onAction?: () => void;
}
export const MyComponent: FC<Props> = ({ title, onAction }) => {
const [count, setCount] = useState(0);
return (
<div>
<h1>{title}</h1>
<p>Count: {count}</p>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
<button onClick={onAction}>Action</button>
</div>
);
};
Component Design
Functional Component Structure
// 1. Imports (grouped and sorted)
import { useState, useEffect } from 'react';
import type { FC, ReactNode } from 'react';
// 2. Types/Interfaces
interface Props {
children: ReactNode;
className?: string;
}
// 3. Component
export const Component: FC<Props> = ({ children, className }) => {
// 4. Hooks (state, effects, context)
const [state, setState] = useState<string>('');
useEffect(() => {
// Side effects
}, []);
// 5. Event handlers
const handleClick = () => setState('clicked');
// 6. Early returns (error states, loading)
if (!children) return null;
// 7. Main render
return <div className={className}>{children}</div>;
};
Container/Presentational Pattern
// Container: Logic and data fetching
export const UserProfileContainer: FC<{ userId: number }> = ({ userId }) => {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(setUser)
.finally(() => setLoading(false));
}, [userId]);
if (loading) return <LoadingSpinner />;
if (!user) return <ErrorMessage />;
return <UserProfile user={user} />;
};
// Presentational: Pure UI
export const UserProfile: FC<{ user: User }> = ({ user }) => (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
);
Core Hooks
useState - Local State
// Basic usage
const [count, setCount] = useState(0);
const [user, setUser] = useState<User | null>(null);
// Functional updates (when new state depends on old)
setCount(prevCount => prevCount + 1);
// Lazy initialization (expensive computation)
const [data, setData] = useState(() => expensiveComputation());
// Object state updates (always spread)
setForm(prev => ({ ...prev, email: 'new@email.com' }));
useEffect - Side Effects
// Run once on mount
useEffect(() => {
fetchData();
}, []);
// Run when dependencies change
useEffect(() => {
fetchUser(userId);
}, [userId]);
// Cleanup function
useEffect(() => {
const subscription = api.subscribe();
return () => subscription.unsubscribe();
}, []);
// Abort fetch on unmount
useEffect(() => {
const controller = new AbortController();
fetch(url, { signal: controller.signal });
return () => controller.abort();
}, [url]);
useContext - Consume Context
interface ThemeContextType {
theme: 'light' | 'dark';
toggleTheme: () => void;
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
// Provider
export const ThemeProvider: FC<{ children: ReactNode }> = ({ children }) => {
const [theme, setTheme] = useState<'light' | 'dark'>('light');
const toggleTheme = () => setTheme(prev => prev === 'light' ? 'dark' : 'light');
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
// Custom hook (always validate context exists)
export const useTheme = () => {
const context = useContext(ThemeContext);
if (!context) throw new Error('useTheme must be used within ThemeProvider');
return context;
};
useReducer - Complex State
type Action = { type: 'increment' } | { type: 'decrement' } | { type: 'reset' };
const reducer = (state: number, action: Action): number => {
switch (action.type) {
case 'increment': return state + 1;
case 'decrement': return state - 1;
case 'reset': return 0;
default: return state;
}
};
const Counter = () => {
const [count, dispatch] = useReducer(reducer, 0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
};
Custom Hooks
function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
const controller = new AbortController();
fetch(url, { signal: controller.signal })
.then(res => res.json())
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
return () => controller.abort();
}, [url]);
return { data, loading, error };
}
// Usage
const { data: user, loading, error } = useFetch<User>(`/api/users/${userId}`);
Performance Optimization
React.memo - Prevent Re-renders
// Memoize component - only re-renders when props change
export const ExpensiveComponent = memo(({ data }: { data: Data }) => {
return <div>{/* expensive rendering */}</div>;
});
// With custom comparison
export const CustomMemo = memo(
({ user }: { user: User }) => <div>{user.name}</div>,
(prev, next) => prev.user.id === next.user.id
);
useMemo & useCallback
// useMemo: Memoize expensive computations
const filteredItems = useMemo(() => {
return items.filter(item => item.includes(filter));
}, [items, filter]);
// useCallback: Memoize function references
const handleClick = useCallback(() => {
setCount(c => c + 1);
}, []);
// Pass to memoized children to prevent re-renders
<MemoizedChild onClick={handleClick} />
Code Splitting
import { lazy, Suspense } from 'react';
const HeavyComponent = lazy(() => import('./HeavyComponent'));
const App = () => (
<Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</Suspense>
);
Accessibility (WCAG 2.1 AA)
Essential Patterns
// Use semantic HTML
<button onClick={handleClick}>Click me</button> // Good
<div onClick={handleClick}>Click me</div> // Bad
// ARIA labels for screen readers
<button aria-label="Close dialog">X</button>
// ARIA descriptions
<input type="email" aria-describedby="email-hint" />
<span id="email-hint">We'll never share your email</span>
// Live regions for dynamic content
<div aria-live="polite" aria-atomic="true">{statusMessage}</div>
// Keyboard navigation
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') onClose();
if (e.key === 'Enter') onSubmit();
};
Form Accessibility
<form onSubmit={handleSubmit}>
<label htmlFor="email">Email</label>
<input
id="email"
type="email"
aria-invalid={!!errors.email}
aria-describedby={errors.email ? 'email-error' : undefined}
/>
{errors.email && <span id="email-error" role="alert">{errors.email}</span>}
</form>
TypeScript Quick Reference
Component Props
interface Props {
title: string; // Required
subtitle?: string; // Optional
variant: 'primary' | 'secondary'; // Union types
onClick?: () => void; // Optional function
onSubmit: (data: FormData) => void; // Required function
children: ReactNode; // Children
user: User; // Complex type
}
export const Component: FC<Props> = ({ title, onClick }) => (
<div onClick={onClick}>{title}</div>
);
Event Handlers
const handleClick = (e: MouseEvent<HTMLButtonElement>) => {};
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {};
const handleSubmit = (e: FormEvent<HTMLFormElement>) => { e.preventDefault(); };
const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {};
Refs
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => { inputRef.current?.focus(); }, []);
<input ref={inputRef} />
Anti-Patterns (Avoid These)
// DON'T: Mutate state directly
user.name = 'Jane'; setUser(user); // Bad
setUser({ ...user, name: 'Jane' }); // Good
// DON'T: Use index as key
{items.map((item, i) => <div key={i}>{item}</div>)} // Bad
{items.map(item => <div key={item.id}>{item}</div>)} // Good
// DON'T: Call hooks conditionally
if (condition) { useState(0); } // Bad - hooks must be top-level
// DON'T: Miss useEffect dependencies
useEffect(() => { fetchUser(userId); }, []); // Bad
useEffect(() => { fetchUser(userId); }, [userId]); // Good
// DON'T: Inline functions in JSX (when performance matters)
<Button onClick={() => handleClick(id)}>Click</Button> // Bad
<Button onClick={handleClickWithId}>Click</Button> // Good (with useCallback)
Testing Quick Reference
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
describe('Button', () => {
it('renders with text', () => {
render(<Button>Click me</Button>);
expect(screen.getByRole('button', { name: /click me/i })).toBeInTheDocument();
});
it('handles click events', async () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click</Button>);
await userEvent.click(screen.getByRole('button'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
it('has no accessibility violations', async () => {
const { container } = render(<Button>Click</Button>);
expect(await axe(container)).toHaveNoViolations();
});
});
Integration Checklist
When using this skill, ensure:
- Components use TypeScript with strict types
- Interactive elements are keyboard accessible
- ARIA attributes added where semantic HTML insufficient
- Performance optimization applied (memo, useMemo, useCallback)
- Unit tests written with React Testing Library
- Accessibility tests with jest-axe
- Custom hooks extracted for reusable logic
- Error boundaries implemented for error handling
See Also
- REFERENCE.md - Comprehensive React guide with:
- Advanced component patterns (compound components, render props, HOCs)
- Complete hooks deep dive
- State management architectures (Context optimization, Redux, Zustand)
- Full WCAG 2.1 AA accessibility guide
- Performance profiling and optimization
- Testing strategies and patterns
- TypeScript advanced patterns
- Styling approaches (CSS Modules, styled-components, Tailwind)
- templates/ - Code generation templates
- examples/ - Real-world implementation examples
Version: 1.0.0 | Last Updated: 2025-01-01 | Status: Production Ready