| name | old-react |
| description | Use when reviewing or refactoring React code in pre-RSC projects (classes, hooks,
Redux/MobX/observable, Reselect, Immer). Applies FP-thinking rules grounded in
render purity, immutable updates, and the Elm Architecture (Model, Msg, update,
view, Cmd, Sub).
Triggers on phrases like "review my React code", "refactor this class component",
"audit hooks usage", "review this reducer", or the slash command `/old-react`.
Out of scope: React Server Components, the `use(promise)` hook, `'use client'`
and `'use server'` boundaries.
|
| license | MIT |
old-react
Review and refactor pre-RSC React code using FP-thinking rules.
When to apply
This skill activates only when the user explicitly asks for review or refactor of pre-RSC React code, or invokes /old-react. Do not auto-apply during unrelated work.
The skill assumes the user is maintaining code written between roughly 2014 and 2023: classes, then hooks, with Redux, MobX, observables, RxJS, and Cycle.js orbiting around it. See the Scope check section for how it handles files that mix the two eras.
Core lens (FP thinking)
Three pillars. Read references/fp-thinking.md for the full treatment.
- Pure render.
view = f(model). No Date.now, Math.random, storage, setState, or ref reads during render.
- Immutable updates. A new state is a new value. Reference equality is what selectors and reconcilers use to detect change.
- Effects at the edges. Effects are descriptions interpreted by a runtime, not callbacks invoked from inside business logic.
The Elm Architecture (TEA) is the shape behind all three. See references/tea-as-backbone.md.
Mode: review
Read the code. Surface violations grouped by category (purity-, immutable-, model-, message-, effect-, hooks-, compose-), prioritized within each group by impact (CRITICAL → HIGH → MEDIUM → LOW). For each finding emit:
[<rule-slug>] (<impact>) <file>:<line>
<one-sentence why>
Before: <minimal snippet>
After: <minimal snippet>
Group ordering: report purity- and immutable- violations first; they undermine reasoning about everything else.
Mode: refactor
Apply rules one at a time. Each refactor produces a minimal diff. If multiple rules apply to one site, fix the highest-impact one first and ask before continuing. Output unified diffs with rationale citing the rule slug.
Never modify code in a span flagged by Scope check as out of scope.
Rule index
The skill exists to teach FP thinking in React UI development, not to maximise rule count. A rule ships only when a recurring architectural failure surfaces in real review and is not already caught by lint or types. Categories without rules below are not abandoned — they defer to existing tooling and add a rule only when a specific gap surfaces.
| Prefix | Concern | Current rules |
|---|
purity- | Pure render and update | purity-no-effect-in-derivation |
immutable- | Update mechanics | (deferred; covered by the immutability diagnostic) |
model- | State architecture (SSOT) | model-single-source-of-truth, model-derive-dont-store, model-controlled-by-default, model-status-as-tagged-union, model-narrow-selector-shape, model-stable-derivation-identity |
message- | Discrete labeled events | (deferred; TypeScript discriminated unions cover the type-level discipline) |
effect- | Cmd/Sub-shaped effects | effect-emit-named-actions, effect-setup-cleanup-pair |
hooks- | React mechanism | hooks-class-fallback-when-needed (hook correctness — react-hooks/rules-of-hooks, react-hooks/exhaustive-deps — remains deferred; this rule governs hook applicability, not correctness) |
compose- | Composition | compose-leaf-purity, compose-effects-at-page-boundary, compose-optional-callbacks, compose-consistent-context-access (no-inline-components covered by the static-components diagnostic and stable react/no-unstable-nested-components) |
Read individual rule files in rules/<slug>.md for the full why + Incorrect/Correct + deeper notes.
Scope check
Apply the following heuristic to every file before review or refactor:
- File-level directives. If line 1 (after optional comments) is
'use client' or 'use server', skip the whole file and report out of scope: directive '<…>' at line 1.
- Async function components. If a top-level component is
async function or export default async function, skip its body but review same-file pure helpers and pure components that don't depend on its output.
use(promise) / use(context) calls. Skip the enclosing component body. Annotate the skipped span with <file>:<start-line>-<end-line>.
- Server actions. Functions whose body begins with
'use server' directive: skip the function. Surrounding pure utilities remain in scope.
- Mixed file. Review only in-scope functions. Emit a
Skipped section listing each out-of-scope span.
- Refactor mode never modifies code inside a skipped span, even when other rules might tangentially apply.
Vocabulary discipline
The rule bodies use FP/TEA pattern terms only: reducer, action, dispatch, store, message, command, subscription, selector, state machine, observable (as a concept), tagged union, effect handler. Library brand names — Redux, MobX, RxJS, TanStack, SWR, Reselect, Immer, XState — and RxJS operator names live in references/lib-suggestions.md.
When recommending a library to the user, link to that reference rather than inlining the suggestion in the finding.
Output protocol
- Review = grouped findings, each citing
<rule-slug> + impact + before/after.
- Refactor = unified diff per rule applied, with rationale citing the rule slug.
- For both modes, end with a one-paragraph summary: how many findings per category, top three most impactful, scope-skipped spans (if any).
References
references/fp-thinking.md — the lens.
references/tea-as-backbone.md — Elm Architecture, lineage Bret Victor → Elm → Redux.
references/hooks-as-slot-table.md — why Rules of Hooks exist.
references/lib-suggestions.md — library brand names and trade-offs.
references/scoreboard.md — how each ecosystem item degrades from its FP/FRP original.
references/advanced-patterns.md — patterns / mental models worth knowing but not enforced (curried updates, nested actions, CPS as the unifying abstraction, time-space duality).