npx skills add ...
npx skills add affaan-m/ecc --skill react-patterns
React 18/19 patterns including hooks discipline, server/client component boundaries, Suspense + error boundaries, form actions, data fetching, state management decision trees, and accessibility-first composition. Use when writing or reviewing React components.
npx skills add affaan-m/ecc --skill react-patterns
Idiomatic React 18/19 patterns for building robust, accessible, performant component trees.
forwardRef/useEffect-heavy codeDerived state in useEffect adds a render cycle, can desync, and obscures the data flow.
Effects, mutations, network calls, and subscriptions live in event handlers or useEffect — never in the render body.
React has no inheritance model for components. Compose with children, render props, or component props.
See rules/react/hooks.md for the full ruleset. Highlights:
setX(prev => prev + 1)) when new state depends on olduseMemo/useCallback only when a profiler or a dependency chain proves it mattersMost pages do not need context or a global store. Resist abstraction until duplicated lifting becomes painful.
Boundaries:
children<form action={...}> or imperatively from event handlersimport a Server Component from a Client Component file — compose them via children insteadreact-error-boundary for a hook-friendly wrapperUse controlled when the value drives other UI, formats on every keystroke, or implements real-time validation.
For multi-step forms, dynamic field arrays, or cross-field validation: use a library (React Hook Form, TanStack Form). Roll-your-own state management for forms past trivial complexity is a maintenance trap.
| Need | Tool |
|---|---|
| Per-request data in Next.js App Router | RSC await fetch() |
| Client-side cache + mutations + invalidation | TanStack Query |
| Lightweight client cache + revalidation | SWR |
| Real-time subscriptions | Server-Sent Events, WebSockets, or the lib's subscription API |
| One-off fire-and-forget | fetch() in an event handler |
Avoid useEffect + fetch for application data — race conditions, no cache, no retry, no Suspense integration.
childrenUseful when the parent needs to pass parameters to the rendered output:
Modern alternative: a hook (useData(id)) returning the same shape — usually cleaner.
React.memo Actually HelpsWrap a component in React.memo only when:
React.memo adds an equality check on every render. If props differ on most renders, the check is pure overhead.
themeContext does not re-render auth consumersuseSyncExternalStore for external state libraries — required for safe concurrent renderingkey props (database id, not array index)@tanstack/react-virtual or react-window once visible item count exceeds ~50 with non-trivial rows<button>, <a>, <nav>, <main>) before reaching for role attributes<label htmlFor> or aria-label if visually labeled by an iconaxe in component tests (see skills/react-testing)This skill is router-agnostic. The patterns above work with React Router, TanStack Router, Next.js App Router, Remix Router. Router-specific patterns (loaders, actions, nested layouts) follow the router's documentation — those are framework concerns layered on top of React core.
react-native-patterns skill (not present yet)react-reviewer for code review, react-build-resolver for build/bundler errors/react-review, /react-build, /react-testuseOptimistic