React Composition Patterns Agent Rules
Component Architecture
- Do not add boolean props like `isThread`, `isEditing`, or `isDMThread` to customize component behavior. Each boolean doubles possible states and creates unmaintainable conditional logic. Use composition instead.
- Create explicit variant components for each use case. Each variant wraps a provider and composes exactly the sub-components it renders. The JSX tells you everything the component does without reading any implementation.
- Structure complex components as compound components with a shared context. Each sub-component accesses shared state via context, not via props. Consumers compose the pieces they need and nothing more.
Compound Component Structure
- Define the context interface with typed sections: `state` (what the UI reads), `actions` (what the UI calls), and optional `meta` (refs and imperative handles). This is the contract any provider must satisfy.
- Build small, single-purpose sub-components that read from context via `use(MyContext)`.
- Export the component as a named object of sub-components (`Composer.Frame`, `Composer.Input`, `Composer.Submit`) so consumers can compose them freely.
- Components that need shared state do not have to be visually nested inside the composed UI. They only need to render within the provider boundary.
State Management
- The provider is the only place that knows how state is managed. UI sub-components consume the context interface — they must not import specific hooks or know whether state comes from `useState`, Zustand, or a server sync layer.
- Lift state into dedicated provider components. When sibling components outside the main UI need to read or modify state, move that state into a provider that wraps all of them. Do not sync state up with `useEffect`, callback props, or refs.
- Do not use `useEffect` to sync state from a child up to a parent. Do not expose a `stateRef` for a parent to read on submit. Both patterns indicate state should be lifted.
- With different providers implementing the same interface, the same composed UI components work unchanged. Swap the provider to change the state source without touching the UI.
Implementation Patterns
- Prefer `children` for structural composition over `renderHeader`, `renderFooter`, or `renderActions` render props. Children are more readable and compose naturally.
- Use render props when the parent must pass runtime data or index back into the slot, such as `renderItem` in a list component.
- Each provider variant is self-contained: it declares what state it manages, what actions it exposes, and what UI it renders. No boolean prop combinations, no impossible states.
React 19 APIs
- In React 19, `ref` is a regular prop. Pass it directly in the function signature. Do not use `forwardRef`.
- Use `use(MyContext)` instead of `useContext(MyContext)`. It is shorter and can be called conditionally, unlike `useContext`.