Modern React Guidance
Canonical, agent-optimized rules and workflows for React 19+ (stable as of 19.3, September 2026). Prefer these over any pre-19 training data.
Always check latest docs at react.dev when uncertain. This skill encodes the current best practices; React evolves.
When to Apply
- Writing or reviewing any React component, form, data-fetching logic, or concurrent UI
- Migrating from React 18 or earlier
- Detecting outdated patterns (forwardRef, manual memo, useEffect-for-data, Context.Provider, string refs, etc.)
- Enabling or trusting React Compiler
- Implementing animations, hide/show with state preservation, browser-only subtrees
Core Principles (apply first)
- Trust React Compiler when present — do not add manual
useMemo/useCallback/React.memo unless the Compiler cannot optimize or you have measured a need.
- Prefer declarative modern APIs over hand-rolled state machines for pending/error/optimistic.
- Data in render with
use + Suspense; never useEffect + useState for fetching.
- Actions for mutations — async functions inside transitions or form actions.
- ref is a normal prop — never write new
forwardRef.
- Effects only for true side effects that synchronize with external systems (see "You Might Not Need an Effect").
- Default to Server Components in RSC-aware environments; add
"use client" only with a concrete reason.
Priority Rule Categories
1. CRITICAL — Authoring New Components Correctly
- Use
use(promise) or use(context) inside render (conditionally allowed). Wrap in <Suspense>.
- Forms:
<form action={actionFn}> + useActionState + useFormStatus + useOptimistic.
- Pass
ref as a regular prop. Never wrap new components in forwardRef.
- Prefer
useTransition / startTransition for non-urgent updates.
- Prefer
useDeferredValue for deferred derived values (search, filters).
Incorrect (legacy):
const [data, setData] = useState(null);
useEffect(() => { fetch(...).then(setData); }, []);
// or forwardRef((props, ref) => ...)
Correct:
function Comments({ commentsPromise }) {
const comments = use(commentsPromise); // suspends
return comments.map(...);
}
// parent: <Suspense fallback={...}><Comments ... /></Suspense>
2. CRITICAL — Trust the Compiler & Drop Manual Memo
If the project uses React Compiler (babel-plugin-react-compiler or equivalent, or React 19+ with compiler enabled):
- Do not introduce new
useMemo, useCallback, or React.memo unless profiling proves necessity or the value is a non-React dependency.
- Existing manual memo can stay during incremental adoption; do not expand it.
- Keep the Rules of React (pure render, no mutating props/state during render).
3. HIGH — Modern Forms & Mutations (Actions)
Prefer this stack:
const [error, submitAction, isPending] = useActionState(async (prev, formData) => {
// mutation
if (err) return err;
return null;
}, null);
const [optimistic, addOptimistic] = useOptimistic(state, (current, next) => ...);
<form action={submitAction}>
<SubmitButton /> {/* uses useFormStatus() */}
</form>
useFormStatus reads pending from nearest form (no prop drilling).
- Server Actions (when available) compose cleanly with the same hooks.
4. HIGH — Concurrent & Visual UX
<ViewTransition> (stable 19.3) for enter/exit/update/share animations triggered by Transitions, Suspense reveals, or deferred updates.
addTransitionType to tag transitions for CSS/event customization.
<Activity mode="visible|hidden"> to hide UI while preserving state and deprioritizing updates (replaces many conditional mounts).
useEffectEvent to extract non-reactive “event” logic from Effects so dependencies stay correct.
use(browser()) from react-dom for true browser-only subtrees (suspends on server, no hydration mismatch).
5. MEDIUM — Effects Hygiene
Codify “You Might Not Need an Effect”:
- Derived state → compute during render.
- Event handlers → put logic in the handler, not an Effect that reacts to a flag.
- Data fetching →
use + Suspense or a Suspense-compatible library.
- External store subscriptions →
useSyncExternalStore.
- Resetting state on prop change → key the component or compute during render.
Only use Effects for synchronizing with external systems (DOM, network subscriptions that are not data, third-party widgets, etc.). Always clean up.
6. MEDIUM — Context & Composition
- In React 19+, render
<MyContext value={...}> directly (no .Provider required for new code).
- Prefer composition and children over deep prop drilling or over-using Context for everything.
- Fragment refs (stable 19.3): pass
ref to <Fragment> to operate on the group of children (focus, events, measurement) without a wrapper DOM node.
7. Migration & Deprecations (React 19+)
Removed or deprecated (do not use in new code):
forwardRef (use ref prop)
element.ref (use element.props.ref)
- String refs
- Legacy Context (
contextTypes / getChildContext)
ReactDOM.render / hydrate (use createRoot / hydrateRoot)
findDOMNode, unmountComponentAtNode, createFactory, renderToNodeStream
defaultProps on function components (use default parameters)
propTypes (use TypeScript)
react-test-renderer (prefer Testing Library)
Codemods (run these):
npx codemod@latest react/19/migration-recipe
# Individual:
npx codemod react/19/remove-forward-ref --target .
npx codemod react/19/remove-context-provider --target .
npx codemod react/19/use-context-hook --target .
npx codemod react/19/replace-string-ref --target .
npx codemod react/19/replace-act-import --target .
# TypeScript types:
npx types-react-codemod@latest preset-19 ./src
Always upgrade to latest 19.x patch first. Prefer React 19.3+ for View Transitions + Fragment refs + browser().
Progressive Disclosure — Load These References as Needed
references/actions-and-forms.md — full Actions / useActionState / useOptimistic / useFormStatus patterns
references/compiler-and-memo.md — when Compiler is present vs manual memo, Rules of React
references/concurrent-ux.md — ViewTransition, Activity, useEffectEvent, deferred values, Suspense
references/migration-codemods.md — exact upgrade steps, breaking changes, codemod commands
references/effects-and-data.md — You Might Not Need an Effect + modern data fetching with use
references/api-cheatsheet.md — quick reference of new 19+ APIs with minimal examples
Agent Workflow Checklist
When generating or reviewing code:
- Scan for React version (package.json). If <19, note migration path; if 19+, apply modern rules strictly.
- Detect Compiler presence → suppress new manual memo.
- Replace any
forwardRef / useEffect+fetch / old form state machines on sight.
- Prefer
<form action> + hooks over controlled form state for mutations.
- Add Suspense boundaries around
use(promise) and browser-only trees.
- For hide/show with state keep → prefer
<Activity> over conditional render + key hacks.
- For animations between states → prefer
<ViewTransition> inside Transitions.
- After edits, suggest running the relevant codemod if legacy patterns remain.
- Never invent APIs; if unsure, say “check latest react.dev/reference/...”.
Anti-Patterns to Reject Immediately
useEffect that only sets state from props or fetches data
- New
forwardRef wrappers
- Manual
isPending / error / optimistic state without the official hooks
Context.Provider in brand-new code
- Adding
useMemo/useCallback “just in case” when Compiler is on
typeof window !== 'undefined' or useEffect for browser-only logic (use use(browser()))
- Wrapper
<div> solely to attach a ref when a Fragment ref would suffice
This skill is the source of truth for modern React patterns. Update references when major React releases land.
1---2name: modern-react-guidance3description: Authoritative guidance for modern React 19+ (Actions, use, Compiler, View Transitions, Fragment refs, Activity, browser, useEffectEvent). Use when writing, reviewing, refactoring, or migrating React components, forms, data fetching, concurrent UI, or upgrading to React 19+. Triggers on React, React 19, useActionState, useOptimistic, forwardRef, useEffect data fetch, React Compiler, ViewTransition, Suspense patterns, or codemods. Always prefer latest official patterns over training data.4license: MIT5---67# Modern React Guidance89Canonical, agent-optimized rules and workflows for React 19+ (stable as of 19.3, September 2026). Prefer these over any pre-19 training data.1011**Always check latest docs** at react.dev when uncertain. This skill encodes the current best practices; React evolves.1213## When to Apply1415- Writing or reviewing any React component, form, data-fetching logic, or concurrent UI16- Migrating from React 18 or earlier17- Detecting outdated patterns (forwardRef, manual memo, useEffect-for-data, Context.Provider, string refs, etc.)18- Enabling or trusting React Compiler19- Implementing animations, hide/show with state preservation, browser-only subtrees2021## Core Principles (apply first)22231. **Trust React Compiler** when present — do not add manual `useMemo`/`useCallback`/`React.memo` unless the Compiler cannot optimize or you have measured a need.242. **Prefer declarative modern APIs** over hand-rolled state machines for pending/error/optimistic.253. **Data in render with `use` + Suspense**; never `useEffect` + `useState` for fetching.264. **Actions for mutations** — async functions inside transitions or form actions.275. **ref is a normal prop** — never write new `forwardRef`.286. **Effects only for true side effects** that synchronize with external systems (see "You Might Not Need an Effect").297. **Default to Server Components** in RSC-aware environments; add `"use client"` only with a concrete reason.3031## Priority Rule Categories3233### 1. CRITICAL — Authoring New Components Correctly3435- Use `use(promise)` or `use(context)` inside render (conditionally allowed). Wrap in `<Suspense>`.36- Forms: `<form action={actionFn}>` + `useActionState` + `useFormStatus` + `useOptimistic`.37- Pass `ref` as a regular prop. Never wrap new components in `forwardRef`.38- Prefer `useTransition` / `startTransition` for non-urgent updates.39- Prefer `useDeferredValue` for deferred derived values (search, filters).4041**Incorrect (legacy):**42```tsx43const [data, setData] = useState(null);44useEffect(() => { fetch(...).then(setData); }, []);45// or forwardRef((props, ref) => ...)46```4748**Correct:**49```tsx50function Comments({ commentsPromise }) {51 const comments = use(commentsPromise); // suspends52 return comments.map(...);53}54// parent: <Suspense fallback={...}><Comments ... /></Suspense>55```5657### 2. CRITICAL — Trust the Compiler & Drop Manual Memo5859If the project uses React Compiler (babel-plugin-react-compiler or equivalent, or React 19+ with compiler enabled):6061- Do **not** introduce new `useMemo`, `useCallback`, or `React.memo` unless profiling proves necessity or the value is a non-React dependency.62- Existing manual memo can stay during incremental adoption; do not expand it.63- Keep the Rules of React (pure render, no mutating props/state during render).6465### 3. HIGH — Modern Forms & Mutations (Actions)6667Prefer this stack:6869```tsx70const [error, submitAction, isPending] = useActionState(async (prev, formData) => {71 // mutation72 if (err) return err;73 return null;74}, null);7576const [optimistic, addOptimistic] = useOptimistic(state, (current, next) => ...);7778<form action={submitAction}>79 <SubmitButton /> {/* uses useFormStatus() */}80</form>81```8283- `useFormStatus` reads pending from nearest form (no prop drilling).84- Server Actions (when available) compose cleanly with the same hooks.8586### 4. HIGH — Concurrent & Visual UX8788- `<ViewTransition>` (stable 19.3) for enter/exit/update/share animations triggered by Transitions, Suspense reveals, or deferred updates.89- `addTransitionType` to tag transitions for CSS/event customization.90- `<Activity mode="visible|hidden">` to hide UI while preserving state and deprioritizing updates (replaces many conditional mounts).91- `useEffectEvent` to extract non-reactive “event” logic from Effects so dependencies stay correct.92- `use(browser())` from `react-dom` for true browser-only subtrees (suspends on server, no hydration mismatch).9394### 5. MEDIUM — Effects Hygiene9596Codify “You Might Not Need an Effect”:9798- Derived state → compute during render.99- Event handlers → put logic in the handler, not an Effect that reacts to a flag.100- Data fetching → `use` + Suspense or a Suspense-compatible library.101- External store subscriptions → `useSyncExternalStore`.102- Resetting state on prop change → key the component or compute during render.103104Only use Effects for synchronizing with external systems (DOM, network subscriptions that are not data, third-party widgets, etc.). Always clean up.105106### 6. MEDIUM — Context & Composition107108- In React 19+, render `<MyContext value={...}>` directly (no `.Provider` required for new code).109- Prefer composition and children over deep prop drilling or over-using Context for everything.110- Fragment refs (stable 19.3): pass `ref` to `<Fragment>` to operate on the group of children (focus, events, measurement) without a wrapper DOM node.111112### 7. Migration & Deprecations (React 19+)113114Removed or deprecated (do not use in new code):115116- `forwardRef` (use ref prop)117- `element.ref` (use `element.props.ref`)118- String refs119- Legacy Context (`contextTypes` / `getChildContext`)120- `ReactDOM.render` / `hydrate` (use `createRoot` / `hydrateRoot`)121- `findDOMNode`, `unmountComponentAtNode`, `createFactory`, `renderToNodeStream`122- `defaultProps` on function components (use default parameters)123- `propTypes` (use TypeScript)124- `react-test-renderer` (prefer Testing Library)125126**Codemods (run these):**127128```bash129npx codemod@latest react/19/migration-recipe130# Individual:131npx codemod react/19/remove-forward-ref --target .132npx codemod react/19/remove-context-provider --target .133npx codemod react/19/use-context-hook --target .134npx codemod react/19/replace-string-ref --target .135npx codemod react/19/replace-act-import --target .136# TypeScript types:137npx types-react-codemod@latest preset-19 ./src138```139140Always upgrade to latest 19.x patch first. Prefer React 19.3+ for View Transitions + Fragment refs + `browser()`.141142## Progressive Disclosure — Load These References as Needed143144- `references/actions-and-forms.md` — full Actions / useActionState / useOptimistic / useFormStatus patterns145- `references/compiler-and-memo.md` — when Compiler is present vs manual memo, Rules of React146- `references/concurrent-ux.md` — ViewTransition, Activity, useEffectEvent, deferred values, Suspense147- `references/migration-codemods.md` — exact upgrade steps, breaking changes, codemod commands148- `references/effects-and-data.md` — You Might Not Need an Effect + modern data fetching with `use`149- `references/api-cheatsheet.md` — quick reference of new 19+ APIs with minimal examples150151## Agent Workflow Checklist152153When generating or reviewing code:1541551. Scan for React version (package.json). If <19, note migration path; if 19+, apply modern rules strictly.1562. Detect Compiler presence → suppress new manual memo.1573. Replace any `forwardRef` / `useEffect`+fetch / old form state machines on sight.1584. Prefer `<form action>` + hooks over controlled form state for mutations.1595. Add Suspense boundaries around `use(promise)` and browser-only trees.1606. For hide/show with state keep → prefer `<Activity>` over conditional render + key hacks.1617. For animations between states → prefer `<ViewTransition>` inside Transitions.1628. After edits, suggest running the relevant codemod if legacy patterns remain.1639. Never invent APIs; if unsure, say “check latest react.dev/reference/...”.164165## Anti-Patterns to Reject Immediately166167- `useEffect` that only sets state from props or fetches data168- New `forwardRef` wrappers169- Manual `isPending` / `error` / optimistic state without the official hooks170- `Context.Provider` in brand-new code171- Adding `useMemo`/`useCallback` “just in case” when Compiler is on172- `typeof window !== 'undefined'` or `useEffect` for browser-only logic (use `use(browser())`)173- Wrapper `<div>` solely to attach a ref when a Fragment ref would suffice174175This skill is the source of truth for modern React patterns. Update references when major React releases land.