react-patterns

Platform: Web and Mobile (shared React patterns). For React Native-specific patterns (Pressable, ScrollView, FlashList, safe areas), see the react-native-patterns skill.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "react-patterns" with this command: npx skills add dralgorhythm/claude-agentic-framework/dralgorhythm-claude-agentic-framework-react-patterns

React Patterns

Platform: Web and Mobile (shared React patterns). For React Native-specific patterns (Pressable, ScrollView, FlashList, safe areas), see the react-native-patterns skill.

Overview

Patterns for building maintainable React applications with TypeScript, leveraging React 19 features and composition patterns.

API Reference: Use Context7 MCP for full React API reference (mcp__context7__resolve-library-id → react ).

Workflows

  • Choose appropriate component composition pattern

  • Apply TypeScript types for props and events

  • Implement custom hooks for shared logic

  • Add performance optimizations where needed

  • Handle loading and error states with Suspense/boundaries

  • Validate component render behavior

Feedback Loops

  • Components render without TypeScript errors

  • Props are properly typed and validated

  • Custom hooks have clear return types

  • No unnecessary re-renders (use React DevTools Profiler)

  • Error boundaries catch component errors

  • Loading states work with Suspense

Reference Implementation

  1. Component Composition

Compound Components

// Shares implicit state between parent and children const TabsContext = createContext<{ activeTab: string; setActiveTab: (id: string) => void } | null>(null);

function Tabs({ children, defaultTab }: { children: ReactNode; defaultTab: string }) { const [activeTab, setActiveTab] = useState(defaultTab); return <TabsContext.Provider value={{ activeTab, setActiveTab }}>{children}</TabsContext.Provider>; }

function Tab({ id, children }: { id: string; children: ReactNode }) { const ctx = use(TabsContext); if (!ctx) throw new Error('Tab must be used within Tabs'); return ( <button role="tab" aria-selected={ctx.activeTab === id} onClick={() => ctx.setActiveTab(id)}> {children} </button> ); }

Slot Pattern

// Named slots for flexible composition interface CardProps { header?: ReactNode; footer?: ReactNode; children: ReactNode; }

function Card({ header, footer, children }: CardProps) { return ( <div className="card"> {header && <div className="card-header">{header}</div>} <div className="card-body">{children}</div> {footer && <div className="card-footer">{footer}</div>} </div> ); }

  1. React 19 Features

use() Hook

// Unwrap promises and context — simpler than useContext function UserProfile({ userPromise }: { userPromise: Promise<User> }) { const user = use(userPromise); // Suspends until resolved return <div>{user.name}</div>; }

useActionState

async function updateUser(prevState: { error?: string }, formData: FormData) { 'use server'; return { error: undefined }; }

function UserForm() { const [state, formAction, isPending] = useActionState(updateUser, {}); return ( <form action={formAction}> <input name="name" disabled={isPending} /> {state.error && <p className="error">{state.error}</p>} <button disabled={isPending}>{isPending ? 'Saving...' : 'Save'}</button> </form> ); }

useOptimistic

function TodoList({ todos }: { todos: Todo[] }) { const [optimisticTodos, addOptimisticTodo] = useOptimistic( todos, (state, newTodo: Todo) => [...state, newTodo] ); async function handleAdd(formData: FormData) { const todo = { id: crypto.randomUUID(), text: formData.get('text') as string }; addOptimisticTodo(todo); await saveTodo(todo); } return ( <form action={handleAdd}> {optimisticTodos.map(todo => <li key={todo.id}>{todo.text}</li>)} <input name="text" /><button>Add</button> </form> ); }

  1. Custom Hooks

// Object return for multiple named values function useAuth() { const [user, setUser] = useState<User | null>(null); const [loading, setLoading] = useState(true); const login = async (credentials: Credentials) => { setUser(await api.login(credentials)); }; return { user, loading, login }; }

// Tuple return for positional access (like useState) function useToggle(initial = false): [boolean, () => void] { const [value, setValue] = useState(initial); return [value, useCallback(() => setValue(v => !v), [])]; }

// Composing hooks function useLocalStorage<T>(key: string, initial: T) { const [value, setValue] = useState<T>(() => { const stored = localStorage.getItem(key); return stored ? JSON.parse(stored) : initial; }); useEffect(() => { localStorage.setItem(key, JSON.stringify(value)); }, [key, value]); return [value, setValue] as const; }

  1. TypeScript + React

// Extend HTML element props interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { variant?: 'primary' | 'secondary'; loading?: boolean; } function Button({ variant = 'primary', loading, children, ...props }: ButtonProps) { return <button className={variant} disabled={loading} {...props}>{loading ? 'Loading...' : children}</button>; }

// Generic components with full type inference interface ListProps<T> { items: T[]; renderItem: (item: T) => ReactNode; keyExtractor: (item: T) => string; } function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) { return <ul>{items.map(item => <li key={keyExtractor(item)}>{renderItem(item)}</li>)}</ul>; }

// Refs as props (React 19+) — forwardRef is deprecated interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> { label: string; ref?: React.Ref<HTMLInputElement>; } function Input({ label, ref, ...props }: InputProps) { return <label>{label}<input ref={ref} {...props} /></label>; }

  1. State Management

useReducer for Complex State

type Action = | { type: 'FETCH_START' } | { type: 'FETCH_SUCCESS'; payload: User[] } | { type: 'FETCH_ERROR'; payload: string };

function reducer(state: { data: User[]; loading: boolean; error: string | null }, action: Action) { switch (action.type) { case 'FETCH_START': return { ...state, loading: true, error: null }; case 'FETCH_SUCCESS': return { ...state, loading: false, data: action.payload }; case 'FETCH_ERROR': return { ...state, loading: false, error: action.payload }; } }

  1. Performance Patterns

// memo + useCallback prevent unnecessary re-renders const ListItem = memo(function ListItem({ item, onDelete }: ItemProps) { return <li>{item.name}<button onClick={() => onDelete(item.id)}>Delete</button></li>; });

function List() { const [items, setItems] = useState<Item[]>([]); const handleDelete = useCallback((id: string) => { setItems(items => items.filter(item => item.id !== id)); }, []); return <>{items.map(item => <ListItem key={item.id} item={item} onDelete={handleDelete} />)}</>; }

// Lazy loading with Suspense const Dashboard = lazy(() => import('./Dashboard')); function App() { return ( <Suspense fallback={<div>Loading...</div>}> <Routes><Route path="/dashboard" element={<Dashboard />} /></Routes> </Suspense> ); }

  1. Error Handling

class ErrorBoundary extends Component<{ children: ReactNode; fallback?: ReactNode }, { hasError: boolean }> { state = { hasError: false }; static getDerivedStateFromError(): { hasError: boolean } { return { hasError: true }; } componentDidCatch(error: Error, info: ErrorInfo) { console.error(error, info); } render() { return this.state.hasError ? (this.props.fallback ?? <div>Something went wrong</div>) : this.props.children; } }

// Wrap async data loading with Suspense function UserProfile({ userId }: { userId: string }) { const user = use(fetchUser(userId)); // Suspends return <div>{user.name}</div>; }

Best Practices

  • Composition over inheritance - Use composition patterns for flexibility

  • Type everything - Leverage TypeScript for compile-time safety

  • Colocate state - Keep state as close to where it's used as possible

  • Extract custom hooks - Share logic across components with hooks

  • Stable references - Use useCallback/useMemo to prevent unnecessary re-renders

  • Error boundaries - Wrap component trees to catch rendering errors

  • Suspense for loading - Use Suspense instead of manual loading states

  • Avoid prop drilling - Use context or composition for deeply nested props

Anti-Patterns

  • Using forwardRef in React 19 - Use ref as a regular prop instead

  • Class components for new code - Use function components and hooks

  • Mutating state directly - Always use setState or reducer actions

  • Missing dependency arrays - Include all dependencies in useEffect/useMemo/useCallback

  • Overusing useMemo/useCallback - Only optimize when necessary (profile first)

  • Context for everything - Use context sparingly; prefer props or state management library

  • Derived state in useState - Compute derived values during render instead

  • useEffect for derived state - Use useMemo or compute directly in render

  • Index as key - Use stable unique IDs for list keys

  • Ignoring TypeScript errors - Never use 'any' or '// @ts-ignore' as shortcuts

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

react-native-reanimated

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

cloud-native-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

brainstorming

No summary provided by upstream source.

Repository SourceNeeds Review