--- name: building-react-components description: Designs and writes React components with clean props APIs, composition over configuration, correct state placement, and hooks-based logic reuse. Use when the user asks to create, refactor, or review a React component, design a component API, decide where state should live, extract a custom hook, or fix prop drilling or unnecessary re-renders. Do not use for CSS layout mechanics (designing-responsive-layouts) or non-React frameworks — adapt the principles manually there. --- # Building React Components ## When to use / when NOT to use - **Use for:** creating or refactoring React components, designing props APIs, placing state, extracting custom hooks, reviewing component structure. - **Do NOT use for:** CSS layout/breakpoint work (designing-responsive-layouts), styling systems (theming-design-tokens), Vue/Svelte/Angular components, or backend data modeling. ## Core rules 1. **Narrow, typed props — no boolean explosions.** One `variant` union beats three flags that can contradict each other. - ✅ `variant: 'primary' | 'danger' | 'ghost'` - ❌ `isPrimary`, `isDanger`, `isGhost` as three separate booleans 2. **Composition over configuration.** When a component grows a prop per content slot, switch to `children` or slot components. - ✅ `` - ❌ `` 3. **State lives at the lowest component that needs it; lift only when shared.** Before `useState`, pick the state's home: server data → query library cache; shareable/bookmarkable → URL; everything else → local state closest to use. - ✅ search text in the `SearchBox`, results in the query cache, filters in the URL - ❌ every field of a page hoisted into one context "to be safe" 4. **Pick controlled or uncontrolled per input and stay consistent.** Controlled (`value` + `onChange`) when other UI reacts per keystroke; uncontrolled (`defaultValue` + read on submit) for plain forms. - ❌ `value` without `onChange`, or switching between the two mid-lifecycle 5. **Extract reusable logic into custom hooks, not wrapper components.** A hook named `useX` returning plain values beats render-props or HOC indirection. - ✅ `const { data, error } = usePolling(url, 5000)` - ❌ ` …} />` 6. **Memoize only after measuring.** No `React.memo`/`useMemo`/`useCallback` by default; add them when the Profiler shows a real re-render cost, and comment why. - ❌ wrapping every callback in `useCallback` "for performance" 7. **One component per file, named exports, file named after the component.** `UserMenu.tsx` exports `UserMenu`; its private subcomponents stay in the same file until reused elsewhere. 8. **Derive, don't sync.** Values computable from existing props/state are computed during render — never mirrored into state with an effect. - ✅ `const fullName = first + ' ' + last` - ❌ `useEffect(() => setFullName(first + ' ' + last), [first, last])` ## Workflow 1. Name the component and write its props type first — if the type needs more than ~7 props or any boolean pair, redesign with rules 1–2. 2. Decide each piece of state's home (rule 3) before writing any `useState`. 3. Implement render logic; derive values instead of syncing state (rule 8). 4. Extract any logic used twice into a custom hook (rule 5). 5. Self-review: re-check every prop against rules 1–2, every `useState` against rules 3 and 8, every memoization against rule 6. Fix violations before delivering. ## Edge cases & failure modes - **Existing codebase conventions conflict with these rules** → match the codebase; note the divergence in one sentence, don't refactor uninvited. - **Class components in the file being edited** → keep the class style for small edits; propose (don't perform) a hooks migration. - **Prop drilling more than 2 levels** → prefer composition (pass the composed element down) before reaching for context. - **Server components (Next.js/RSC)** → hooks and state are client-only; add `'use client'` only at the interactive leaf, not the page root. ## References Copy-paste patterns and gotchas: see [references/patterns.md](references/patterns.md)