Skip to main content

Writing React Components

Build clean, modern React components that apply common best practices and avoid common pitfalls like unnecessary state management or useEffect usage

Source: .agents/rules/clean-react.mdc

Metadata

  • name: clean-react
  • alwaysApply: true

Content

Writing React Components

We are using modern React (19+) and following common best practices focused on clarity, correctness, and maintainability.

Component Structure & Style

  • PREFER small, focused components with a single responsibility.
  • PREFER named function components over arrow functions.
    • Exception: anonymous callbacks, inline render props, and closures.
  • PREFER explicit return types and props typing (TypeScript) where applicable.
  • Keep components flat and readable; avoid deeply nested JSX.
  • Group related logic together (event handlers, derived values, helpers).

State Management

  • AVOID useEffect().
    • See the You Might Not Need An Effect guide for detailed guidance.
    • PREFER deriving values during render instead of synchronizing state.
    • Fetch data via TanStack Query (@tanstack/react-query).
  • AVOID unnecessary useState() or useReducer() usage.
    • Derive state from props or other state when possible.
    • Localize state to the lowest possible component.
  • DO NOT mirror props in state unless absolutely necessary.
  • Prefer controlled components over syncing uncontrolled state.

Rendering & Derivation

  • PREFER computing derived values inline or via helper functions.
  • Use useMemo() sparingly and only for proven performance issues.
  • AVOID premature optimization.
  • Keep render logic deterministic and free of side effects.

Event Handling

  • AVOID inline event handlers in JSX.
  • PREFER:
function handleClick() {
// ...
}

<button onClick={handleClick} />;

Over:

<button
onClick={() => {
// ...
}}
/>
  • Name handlers clearly (handleSubmit, handleChange, handleClose).
  • Keep handlers small; extract complex logic into helpers.

Effects, Data, and Side Effects

  • AVOID effects for:
    • Derived state
    • Data transformations
    • Event-based logic that can live in handlers
  • If side effects are unavoidable, keep them minimal, isolated, and well-documented.
  • Prefer framework-level or external abstractions (routers, data libraries) over raw effects.

Props & Composition

  • PREFER composition over configuration.
  • AVOID excessive boolean props; prefer expressive APIs.
  • AVOID prop drilling render-only decisions through parents that do not own the UI.
    • If a condition only controls whether a child renders part of its own UI, compute it in that child when it already has access to the needed context, hooks, or local data.
    • Keep the decision close to the rendered markup so future changes are easy to reason about.
    • Pass a prop only when the parent is intentionally choosing a behavior mode, the child must stay context-free/reusable, or the child cannot access the needed data cleanly.
  • Use children intentionally and document expected structure.
  • Keep prop names semantic and predictable.

Performance & Stability

  • PREFER stable references only when required (not by default).
  • AVOID unnecessary memoization (memo, useCallback) unless absolutely required.
  • Keep keys stable and meaningful when rendering lists.

General Principles

  • Write code for humans first, compilers second.
  • Prefer explicitness over cleverness.
  • Optimize for readability and long-term maintenance.
  • If a pattern feels complex, reconsider the component boundary.