//
Search across all documentation pages
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
React 19 is a major release that introduces server-first architecture, new hooks, and automatic optimizations. Here is the quick-reference checklist of what shipped:
Feature Category
------- --------
Server Components (RSC) Architecture
Server Actions Data mutations
Form Actions DOM integration
use() hook Data fetching / context
useActionState Form state management
useFormStatus Pending UI
useOptimistic Optimistic updates
ref as prop API simplification
Document Metadata SEO / head management
Asset Loading APIs Performance
React Compiler Auto-memoizationWhen to reach for this: Read this page first when starting a new React 19 project or planning a migration from React 18.
// A single component that touches many React 19 features at once
import { use, useOptimistic, useActionState } from "react";
import { saveComment } from "./actions"; // server action
type Comment = { id: string; text: string };
function CommentThread({ commentsPromise }: { commentsPromise: Promise<Comment[]> }) {
// use() unwraps the promise (Suspense-aware)
const comments = use(commentsPromise);
// useOptimistic for instant feedback
const [optimistic, addOptimistic] = useOptimistic(
comments,
(state, newText: string) => [...state, { id: "temp", text: newText }]
);
// useActionState to wire up a server action
const [_state, formAction, isPending] = useActionState(
async (_prev: Comment[], formData: FormData) => {
const text = formData.get("text") as string;
addOptimistic(text);
await saveComment(text);
return [...comments, { id: crypto.randomUUID(), text }];
},
comments
);
return (
<section>
{/* Document metadata hoisted to <head> automatically */}
<title>Comments ({optimistic.length})</title>
<meta name="description" content="Live comment thread" />
<ul>
{optimistic.map((c) => (
<li key={c.id}>{c.text}</li>
))}
</ul>
<form action={formAction}>
<input name="text" required />
<button disabled={isPending}>Post</button>
</form>
</section>
);
}
// ref as prop - no forwardRef needed
function FancyInput({ placeholder, ref }: { placeholder: string; ref?: React.Ref<HTMLInputElement> }) {
return <input placeholder={placeholder} ref={ref} />;
}
export { CommentThread, FancyInput };What this demonstrates:
use() unwrapping a promise inside a componentuseOptimistic for instant UI feedbackuseActionState binding a server action to a form<title>, <meta>) rendered inlineref received as a regular prop without forwardRef"use server" that the framework turns into RPC endpoints. They can be passed to forms, called from event handlers, or invoked from transitions.<form action={fn}>. React manages the pending state, error handling, and optimistic updates automatically.useFormState. It returns [state, action, isPending] and works both on the client and with progressive enhancement on the server.<form> to any descendant component.forwardRef is no longer required. Function components receive ref as a regular prop. forwardRef still works but is deprecated and will be removed in a future version.<title>, <meta>, <link>) rendered anywhere in the component tree are automatically hoisted to <head>.preload, preinit, prefetchDNS, preconnect) from react-dom let you eagerly load fonts, scripts, and stylesheets.useMemo, useCallback, and React.memo in most cases.React 19 works in two main modes:
use(), optimistic updates, metadata hoisting, and the compiler. No server components or server actions.@types/react and @types/react-dom (version 19+). Install them together.ref is now part of the props type. If you use React.ComponentProps<typeof MyComponent>, it will include ref automatically.useActionState is generic: useActionState<State>(action, initialState).use() function is generic: use<T>(resource: Promise<T> | React.Context<T>): T.useFormState was renamed. Fix: Replace all useFormState imports with useActionState from "react" (not "react-dom").forwardRef still works but triggers a deprecation warning in development. Fix: Refactor to accept ref as a regular prop.<Context> can now be rendered directly instead of <Context.Provider>. The .Provider syntax still works but is deprecated. Fix: Replace <MyContext.Provider value={v}> with <MyContext value={v}>.undefined implicitly) will be flagged. Fix: If your ref callback returns nothing, ensure it explicitly returns undefined or returns a cleanup.| Approach | When to choose |
|---|---|
| Stay on React 18 | Large app with no immediate need for server components or new hooks |
| Incremental adoption | Add "use client" to existing components and adopt React 19 features file-by-file |
| Full rewrite with RSC | Greenfield project using Next.js 15+ or a framework with RSC support |
| React 19 client-only | SPA that benefits from use(), optimistic updates, and the compiler without server infra |
"use client"use() for reading promises and context (can be called conditionally)useActionState for form state management (replaces useFormState)useFormStatus for pending UI in form descendantsuseOptimistic for instant optimistic updatespreload, preinit, prefetchDNS, preconnectuse(), optimistic updates, metadata hoisting, and the React CompileruseFormState was renamed to useActionState before the stable release"react", not "react-dom"useActionState(action, initialState) returning [state, action, isPending]Tags like <title>, <meta>, and <link> rendered anywhere in the component tree are automatically hoisted to <head>:
function Page() {
return (
<div>
<title>My Page</title>
<meta name="description" content="Hello" />
<h1>Content</h1>
</div>
);
}ref as a regular propforwardRef still works but is deprecated and will be removed in a future versionref from the forwardRef second argument into the props objectundefined from an arrow function expression) will be flagged as a warningconst [state, action, isPending] = useActionState<MyState>(
async (prev: MyState, formData: FormData) => {
// return new state
return { ...prev, updated: true };
},
{ updated: false }
);useActionState is generic: useActionState<State>(action, initialState)(prevState: State, formData: FormData) => Promise<State>use<T>(resource: Promise<T> | React.Context<T>): T"react": import { use } from "react"useMemo, useCallback, and React.memo in most casesuse() can be called conditionally (inside if blocks, loops, early returns) while useContext cannotuse() also accepts promises, not just context objectsuse(context) is the preferred replacement for useContext(context) going forward"use client" to existing components and adopt features file-by-file@types/react and @types/react-dom version 19+) togetheruseFormState imports with useActionState from "react"<Context.Provider> with <Context value={v}> (optional, old syntax still works)<form action={}>, useActionState, useFormStatusReviewed by Chris St. John·Last updated Jul 19, 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥