react-principles
React Development Principles
Component Model
- Components are pure functions:
(props, state) → JSX. Render must be side-effect-free. - One-way data flow: parent → child via props, child → parent via callbacks.
- Never mutate state or props in-place.
Thinking in React: Design Process
- Hierarchy — decompose by SRP; one component, one concern. Map data model shape to component tree.
- Static first — props only, no state, until the skeleton renders correctly.
- Minimal state — DRY: if it's derivable, it's not state.
- Ownership — hoist state to the closest common ancestor of all consumers.
- Inverse flow — pass setters/handlers down; children call them on interaction.
What is NOT state
- Computable from existing state or props → derive during render
- Passed in as a prop
- Unchanged over time
Prefer storing IDs/primitives; derive full objects at render time.
Effect Discipline
useEffect is for synchronizing with external systems only — DOM APIs, network connections, third-party widgets, browser subscriptions. It is not a lifecycle hook and not a data-transformation pipeline.
Deciding when to write an Effect
Why does this code run?
- Because the user did something → event handler
- Because the component must stay in sync with something external → Effect
Unnecessary Effects — replace with:
| Antipattern | Correct approach |
|---|---|
Derived state via useEffect + useState |
Compute during render; useMemo if expensive |
| State reset on prop change via Effect | key prop |
| Partial state adjustment on prop change | Store primitive ID; derive object during render |
| Shared event logic routed through state+Effect | Extract a plain function; call from event handlers |
| User-initiated POST in Effect | Move directly into the event handler |
| Effect chains (A → Effect → B → Effect → C) | Compute all next state in one event handler |
| Parent notification via Effect | Call both setters in the same event handler; or lift state |
| Pushing data up to parent via Effect | Parent fetches; passes data down as prop |
| One-time app init in component Effect | Module-level or didInit guard outside component |
| External store subscription via Effect | useSyncExternalStore |
| Data fetch without cleanup | ignore flag cleanup; prefer framework data-fetching |
Effect rules
- Every reactive value the Effect reads must be in its dependency array.
- Never suppress
react-hooks/exhaustive-deps— fix the code. - Every resource acquired in setup must be released in cleanup.
- One Effect = one synchronization concern. Split unrelated concerns.
- Think start sync / stop sync, not mount / unmount.
Key Heuristics
- If it's computable at render time — compute it. No state, no Effect.
- If it runs because the user did X — it's an event handler.
- If it runs because the component is visible — it's an Effect.
- If two state variables drift out of sync — lift state or derive one from the other.
- If the dep array is long — the Effect does too much; split it.
- If you want to suppress the deps linter — redesign instead.
Supporting Reference Files
Load these files when deeper guidance is needed for the specific topic at hand:
- Eliminating unnecessary Effects (derived state, event logic, Effect chains, data fetching): see references/not-need.md
- Effect lifecycle, reactive values, and dependency contract: see references/lifecycle.md
- Distinguishing event handlers from Effects, and using
useEffectEvent: see references/separating.md - Strategies to reduce and stabilize Effect dependencies: see references/dependencies.md
- Extracting reusable logic into custom hooks: see references/reusing.md
More from discountry/ritmex-skills
use-ctx7
Fetch up-to-date library documentation via the ctx7 CLI. Use PROACTIVELY whenever any code change, feature design, or implementation or user request involves a project dependency — always query the matching version's docs first before writing code.
30codex-prompt-optimize
>
8slack
Control Slack via the `slack` CLI to read, search, and manage messages, threads, files, reactions, channels, DMs, and canvases. Trigger on requests involving Slack messages, threads, URLs, channel history, unread or recent DMs, or sending/replying to messages (English or Chinese queries mentioning Slack).
3debug
>
2refactor
>
2clickup
Use for ClickUp tasks and docs. Trigger on ClickUp URLs, task IDs, list IDs, doc IDs, page IDs, assignees, statuses, due dates, comments, checklists, and document workflows. Use the global `clickup` CLI.
2