---
description: React component patterns with TypeScript examples. Composition, compound components, custom hooks, Context+Reducer state, memoization, code splitting, virtualization, error boundaries, accessibility, and animations.
---
# Frontend Development Patterns
Modern frontend patterns for React, Next.js, and performant user interfaces.
## Component Patterns
### Composition Over Inheritance
```typescript
interface CardProps {
children: React.ReactNode
variant?: 'default' | 'outlined'
}
export function Card({ children, variant = 'default' }: CardProps) {
return
{children}
}
export function CardHeader({ children }: { children: React.ReactNode }) {
return {children}
}
export function CardBody({ children }: { children: React.ReactNode }) {
return {children}
}
```
### Compound Components
```typescript
interface TabsContextValue {
activeTab: string
setActiveTab: (tab: string) => void
}
const TabsContext = createContext(undefined)
export function Tabs({ children, defaultTab }: {
children: React.ReactNode
defaultTab: string
}) {
const [activeTab, setActiveTab] = useState(defaultTab)
return (
{children}
)
}
export function Tab({ id, children }: { id: string, children: React.ReactNode }) {
const context = useContext(TabsContext)
if (!context) throw new Error('Tab must be used within Tabs')
return (
)
}
```
## Custom Hooks Patterns
### Async Data Fetching Hook
```typescript
export function useQuery(
key: string,
fetcher: () => Promise,
options?: { onSuccess?: (data: T) => void; onError?: (error: Error) => void; enabled?: boolean }
) {
const [data, setData] = useState(null)
const [error, setError] = useState(null)
const [loading, setLoading] = useState(false)
const refetch = useCallback(async () => {
setLoading(true)
setError(null)
try {
const result = await fetcher()
setData(result)
options?.onSuccess?.(result)
} catch (err) {
const error = err as Error
setError(error)
options?.onError?.(error)
} finally {
setLoading(false)
}
}, [fetcher, options])
useEffect(() => {
if (options?.enabled !== false) refetch()
}, [key, refetch, options?.enabled])
return { data, error, loading, refetch }
}
```
### Debounce Hook
```typescript
export function useDebounce(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState(value)
useEffect(() => {
const handler = setTimeout(() => setDebouncedValue(value), delay)
return () => clearTimeout(handler)
}, [value, delay])
return debouncedValue
}
```
## State Management: Context + Reducer
```typescript
type Action =
| { type: 'SET_ITEMS'; payload: Item[] }
| { type: 'SELECT_ITEM'; payload: Item }
| { type: 'SET_LOADING'; payload: boolean }
function reducer(state: State, action: Action): State {
switch (action.type) {
case 'SET_ITEMS': return { ...state, items: action.payload }
case 'SELECT_ITEM': return { ...state, selectedItem: action.payload }
case 'SET_LOADING': return { ...state, loading: action.payload }
default: return state
}
}
```
## Performance Optimization
### Memoization
- `useMemo` for expensive computations
- `useCallback` for functions passed to children
- `React.memo` for pure components
### Code Splitting & Lazy Loading
```typescript
const HeavyChart = lazy(() => import('./HeavyChart'))
}>
```
### Virtualization for Long Lists
Use `@tanstack/react-virtual` for lists with many items.
## Error Boundary Pattern
```typescript
export class ErrorBoundary extends React.Component<
{ children: React.ReactNode },
{ hasError: boolean; error: Error | null }
> {
state = { hasError: false, error: null }
static getDerivedStateFromError(error: Error) {
return { hasError: true, error }
}
render() {
if (this.state.hasError) {
return Something went wrong
{this.state.error?.message}
}
return this.props.children
}
}
```
## Animation: Framer Motion
```typescript
{items.map(item => (
))}
```
## Accessibility
- Semantic HTML first (button, nav, main, article)
- Keyboard navigation: ArrowDown/Up, Enter, Escape
- Focus management for modals (save/restore focus)
- ARIA attributes only when semantic HTML is insufficient
$ARGUMENTS