92 lines
4.3 KiB
Markdown
92 lines
4.3 KiB
Markdown
# React Composition Rules
|
|
|
|
This reference distills the upstream Vercel `composition-patterns` skill. The
|
|
upstream directory was inspected as a whole: `SKILL.md`, `README.md`,
|
|
`metadata.json`, generated `AGENTS.md`, `_sections.md`, `_template.md`, and all
|
|
rule files under `rules/`.
|
|
|
|
## Rule Inventory
|
|
|
|
| Area | Rule | Use it to |
|
|
| --- | --- | --- |
|
|
| Architecture | Avoid boolean prop proliferation | Replace mode booleans with explicit composed variants. |
|
|
| Architecture | Use compound components | Let consumers arrange subcomponents that share context. |
|
|
| State | Decouple state management from UI | Keep concrete hooks/stores inside providers. |
|
|
| State | Define generic context interfaces | Share UI across providers using `state`, `actions`, `meta`. |
|
|
| State | Lift state into providers | Let outer/sibling components access composer-like state without refs or effects. |
|
|
| Patterns | Create explicit component variants | Make each mode self-documenting and impossible-state-free. |
|
|
| Patterns | Prefer children over render props | Use children for structure; reserve render props for data callbacks. |
|
|
| React 19 | Ref and context API changes | Use ref as a prop and `use(Context)` when the codebase is React 19+. |
|
|
|
|
## Core Principles
|
|
|
|
- Composition over configuration: let consumers assemble behavior from parts
|
|
instead of adding props for every mode.
|
|
- State belongs at the provider boundary when more than one child or sibling
|
|
needs it.
|
|
- Compound internals should read shared context, not receive long prop chains.
|
|
- Explicit variants are clearer than a single component with many conditional
|
|
branches.
|
|
|
|
## Refactoring Checklist
|
|
|
|
1. Count behavior flags and conditional branches. Two or more mode booleans are
|
|
a strong signal to split variants.
|
|
2. Identify shared primitives. Extract the stable pieces first: frame, input,
|
|
header, footer, trigger, content, action, item, or slot-like sections.
|
|
3. Decide the provider boundary. Put it around every component that needs the
|
|
shared state, even if some of those components are visually outside the main
|
|
frame.
|
|
4. Define the context shape before wiring UI. Prefer:
|
|
|
|
```ts
|
|
interface ComponentContextValue {
|
|
state: ComponentState
|
|
actions: ComponentActions
|
|
meta: ComponentMeta
|
|
}
|
|
```
|
|
|
|
5. Move implementation-specific hooks into provider variants. For example,
|
|
`LocalComposerProvider`, `ChannelComposerProvider`, and
|
|
`EditComposerProvider` can implement the same UI contract.
|
|
6. Replace `renderX` props with children when the consumer is only placing
|
|
static structure.
|
|
7. Keep render props when the parent must provide data to each render, such as
|
|
list items, indices, or measured layout values.
|
|
8. For React 19 code, avoid adding new `forwardRef` wrappers unless compatibility
|
|
with React 18 or an existing library API requires it.
|
|
|
|
## Review Smells
|
|
|
|
- A component accepts several props named `is*`, `show*`, `has*`, or `mode` and
|
|
uses them to render different major sections.
|
|
- A caller can pass contradictory props, such as `isEditing` and `isForwarding`.
|
|
- A reusable UI component imports a feature store, route-specific hook, or sync
|
|
mechanism directly.
|
|
- State is copied upward through `useEffect` solely so another sibling can read
|
|
it.
|
|
- A submit button reads state from a ref because the state is trapped inside a
|
|
child component.
|
|
- `renderHeader`, `renderFooter`, or `renderActions` props are used only to place
|
|
static nodes.
|
|
|
|
## Repo Adaptation
|
|
|
|
- Put generic primitives in `src/shared/ui/<Component>/` with the repo's usual
|
|
source, SCSS module, test, story, and barrel layout.
|
|
- Keep feature-specific provider variants out of `shared` if they import
|
|
feature/entity/page state.
|
|
- Export public compound pieces through `index.ts` instead of deep imports.
|
|
- Coordinate with `react-best-practices` for performance, Server Component
|
|
boundaries, serialization, and client bundle impact.
|
|
- Coordinate with `storybook-ai-best-practices` when adding stories so each
|
|
compound part, variant, and state has focused examples.
|
|
|
|
## Source Notes
|
|
|
|
The upstream skill is version `1.0.0`, dated January 2026, and references React
|
|
documentation for context and the `use` API. Its generated `AGENTS.md` is a
|
|
compiled form of the individual rules, so prefer this distilled reference for
|
|
day-to-day work and consult the upstream repo only when refreshing the skill.
|