React 19 Patterns
Conventions for the new React 19 APIs. This page covers what changed; the baseline hooks rules and linting live in React.
React 19 is stable (December 2024). It adds first-class support for async mutations ("Actions"), a use API, and several ergonomic cleanups. Adopt these patterns for new code. Source: React, https://react.dev/blog/2024/12/05/react-19, 2026-05-31
Actions over manual pending/error state
Async functions run inside transitions are "Actions." They manage pending state, errors, and optimistic updates for you, so stop hand-rolling isPending/error useState triads:
const [error, submitAction, isPending] = useActionState(
async (_prev, formData: FormData) => {
const err = await updateName(formData.get("name") as string);
return err ?? null;
},
null,
);
return <form action={submitAction}>{/* ... */}</form>;
- Pass functions to
<form action={...}>; the form resets automatically on success. - Use
useFormStatusin nested submit buttons instead of prop-drilling pending state. - Use
useOptimisticfor instant feedback that auto-reverts on failure.
Source: React 19 release, 2026-05-31
The use API
Read a promise or context with use(...). Unlike hooks, use may be called conditionally and inside loops, pair it with a Suspense boundary when reading a promise. Do not use it to kick off fetches in render; resolve data in a Server Component or a framework loader and pass the promise down. Source: React 19 release, 2026-05-31
Ergonomic cleanups
refis a regular prop. Writefunction Input({ ref }: Props); do not reach forforwardRefin new components.<Context>is its own provider. Render<ThemeContext value={...}>, not<ThemeContext.Provider>.- Document metadata hoists. Render
<title>,<meta>, and<link>anywhere in a component and React hoists them to<head>. - ref callbacks may return a cleanup function, mirroring effect cleanup.
Source: React 19 release, 2026-05-31
Keep the baseline rules
React 19 does not relax the Rules of Hooks, exhaustive deps, or the architecture-policy lint rules in React. Actions reduce the need for useEffect-based data mutations, which aligns with the no-fetch-in-effect rule, prefer an Action or a framework loader over fetching in an effect.
Adoption Contract
| API | Use when | Do not use when |
|---|---|---|
| Actions | A mutation maps naturally to a form, button, or transition | The operation is read-only data loading |
useActionState |
The UI needs result, error, and pending state from one mutation | Pending/error state is global or cross-route |
useFormStatus |
A nested submit control needs form pending state | The status is unrelated to the nearest form |
useOptimistic |
The optimistic UI can be reverted cleanly | The rollback would be ambiguous or destructive |
use(...) |
A promise/context is already supplied by server/framework code | You would start a fetch during render |
Proof
React 19 migration is complete only after the old manual pending/error path is removed, the error branch is rendered, the success branch resets or preserves state intentionally, and optimistic rollback is exercised. New APIs should reduce state surface, not create a parallel one.
Style Rule Contract
This page follows Style Rule Contract: name the default pattern, banned pattern, reason, exception, proof, and codification path clearly enough that the next agent can apply the rule without asking Kevin again. If a local repo has a stricter rule, follow the local rule and update the wiki when the decision becomes durable.
Timeline
- 2026-07-01 | Aligned this page with Style Rule Contract so style guidance names default behavior, banned patterns, exceptions, proof, and codification expectations. Source: User request, 2026-07-01
- 2026-07-01 | Added an adoption contract and proof checklist for React 19 Actions, form status, optimistic updates, and
use(...)migration. Source: User request, 2026-07-01 - 2026-05-31 | Page created from the React v19 stable release notes. Captured Actions (
useActionState,useFormStatus,useOptimistic,<form action>), theuseAPI, ref-as-prop,<Context>as provider, and document-metadata hoisting; deferred hooks/lint baseline to React. Source: https://react.dev/blog/2024/12/05/react-19, 2026-05-31