React 19 is the major version of React released in December 2024. It adds Actions (async functions that manage pending state, errors and forms), the hooks useActionState, useOptimistic and use, ref as a regular prop, and <title> and <meta> tags that React moves into the document head. React 19.2 (October 2025) added <Activity> and useEffectEvent.
Every example below runs on React 19.2. Here is an Action: an async function passed to a form, with the pending state and the returned error handled by useActionState.
Press Save with the field empty to see the error, then type a name and save: the button reads "Saving..." for 800 ms. There is no useState for the error, no isLoading flag and no e.preventDefault().
Actions and form actions
In React 18 you wrote the same steps for every form: prevent the default submit, set a loading flag, await the request, store an error, clear the flag. React 19 calls a function that does async work inside a transition an Action, and does that bookkeeping for you.
startTransition(anduseTransition) now accept an async function.isPendingstaystrueuntil the whole function finishes.<form action={fn}>callsfnwith the form'sFormDatawhen the form is submitted. It runs as an Action, and after it finishes React resets the form's uncontrolled fields.<button formAction={fn}>gives one submit button its own action.- useActionState keeps the value the action last returned, so an action can return an error message or the saved record.
useFormStatusfromreact-domlets a component inside a form read whether that form is submitting, without passing props down. It needs a parent<form>, so here it appears in a static block:
import { useFormStatus } from 'react-dom';
function SubmitButton() {
const { pending } = useFormStatus();
return <button disabled={pending}>{pending ? 'Sending...' : 'Send'}</button>;
}
useOptimistic
useOptimistic shows the result you expect while an Action is still running, and falls back to the real state when the Action ends. A like counter can go up the moment you click, and drop back if the request fails.
const [optimisticLikes, addOptimisticLike] = useOptimistic(likes, (current, delta) => current + delta);
The useOptimistic page has a runnable example with a fake API that fails on purpose, so you can watch the rollback.
The use API
use reads a value from a promise or from a context. With a promise it suspends the component until the promise resolves, and the nearest <Suspense> shows its fallback meanwhile. Unlike every other hook, use can be called inside an if or a loop, and after an early return.
React 19 also lets you render <ThemeContext value="dark"> directly instead of <ThemeContext.Provider>. Both appear in this example:
ref as a prop, and ref cleanup
A function component now receives ref like any other prop. You no longer need to wrap it in forwardRef to pass a ref through to a DOM element.
A ref callback can also return a cleanup function. React calls it when the element leaves the screen, the same way an effect's cleanup works. A callback that returns nothing is still called with null on removal, as in React 18.
Click the button a few times and read the console: every removal logs the cleanup line, every return logs attached to DIV.
Document metadata
You can render <title>, <meta> and <link> anywhere in a component, and React moves them into <head>. A page component can set its own title without a library such as react-helmet.
The preview has no browser tab to show, so the effect logs document.title instead. Switch articles and the logged title follows.
Stylesheets got the same treatment: <link rel="stylesheet" href="..." precedence="default" /> inside a component is inserted into the head once, in precedence order, and React waits for it before showing the content that needs it. An <script async src="..."> rendered by several components loads only once. react-dom also exports preload, preinit, preconnect and prefetchDNS for resource hints.
Activity and useEffectEvent (React 19.2)
<Activity mode="hidden"> hides its children without throwing away their state. React hides the DOM, runs the effects' cleanups, and restores everything when the mode becomes "visible" again. It suits tabs and panels you expect the user to come back to.
Type a note, switch to About and back. The text is still there, and the console shows the effect cleaned up while hidden. Replace the <Activity> wrapper with {tab === 'notes' && <Notes />} and the note is lost on every switch.
useEffectEvent takes a function out of an effect's dependencies. The function always sees the latest props and state, but changing them does not restart the effect:
function ChatRoom({ roomId, theme }) {
const onConnected = useEffectEvent(() => {
showNotification('Connected!', theme);
});
useEffect(() => {
const connection = createConnection(roomId);
connection.on('connected', () => onConnected());
connection.connect();
return () => connection.disconnect();
}, [roomId]); // theme is not a dependency
}
19.2 also added cacheSignal for Server Components (it tells you when a cache() result is no longer needed) and Performance Tracks in the Chrome DevTools performance panel. React 19.1 added captureOwnerStack, a development-only function that returns which components rendered the current one.
Server Components and Server Functions
Server Components are components that run ahead of time on the server (or at build time) and send their output to the browser. They can be async and read a database directly, and their code never ships to the client. Server Functions (first called Server Actions) are async functions marked with 'use server' that a client component can call like a normal function. Both need a framework with a bundler that supports them, such as the Next.js App Router, so they cannot run in this editor.
// A Server Component: async, runs on the server only
export default async function Notes() {
const notes = await db.notes.findMany();
return notes.map((note) => <Note key={note.id} note={note} />);
}
// A Server Function, usable as a form action
async function createNote(formData) {
'use server';
await db.notes.create({ text: formData.get('text') });
}
Removed and changed APIs
React 19 removed APIs that had been deprecated for years:
| Removed | Use instead |
|---|---|
ReactDOM.render, ReactDOM.hydrate | createRoot, hydrateRoot from react-dom/client |
unmountComponentAtNode | root.unmount() |
findDOMNode | a ref on the DOM element |
String refs (ref="input") | useRef or a ref callback |
Legacy context (contextTypes, getChildContext) | createContext with static contextType or use |
propTypes checks (now silently ignored) | TypeScript, or your own checks |
defaultProps on function components | default parameter values |
react-dom/test-utils | act from react; React Testing Library for the rest |
react-test-renderer/shallow | the react-shallow-renderer package |
React.createFactory | JSX |
Class components keep defaultProps. Errors are also reported differently: errors caught by an error boundary are logged with console.error once, uncaught errors go to window.reportError, and createRoot accepts onCaughtError and onUncaughtError options to report them yourself.
Upgrading to React 19
Upgrade to React 18.3 first. It is identical to 18.2 but warns about the deprecated APIs and other changes React 19 needs, so you can fix them while the app still works. React 19 also requires the modern JSX transform, which Vite and every current framework already use. Then install React 19:
npm install react@^19 react-dom@^19
npm install --save-dev @types/react@^19 @types/react-dom@^19
The official upgrade guide points to codemods for the mechanical changes. The first covers string refs, act imports and ReactDOM.render; the second updates TypeScript code for the new types:
npx codemod@latest react/19/migration-recipe
npx types-react-codemod@latest preset-19 ./src
After upgrading, nothing forces you to adopt Actions or the new hooks. Existing components, hooks and class components keep working; you can move forms over to <form action> one at a time.
Frequently Asked Questions
When was React 19 released?
React 19 became stable in December 2024. React 19.1 followed in March 2025 and React 19.2 in October 2025.
What are the biggest changes in React 19?
Actions (async functions that handle pending state, errors and forms for you), the hooks useActionState, useOptimistic and use, ref as a normal prop, <Context> as a provider, and <title> and <meta> tags that move to the document head. Server Components became stable for frameworks.
Is forwardRef deprecated in React 19?
Function components can now take ref as a regular prop, so new code does not need forwardRef. It still works, and the React team has said it will be deprecated in a future version.
Does React 19 break my React 18 app?
Mostly through APIs that were removed: ReactDOM.render, findDOMNode, string refs, legacy context, propTypes, and defaultProps on function components. React 19 also requires the modern JSX transform. Upgrade to React 18.3 first, fix its deprecation warnings, then run the React 19 codemods.
Do I need Next.js to use React 19?
No. Actions, the new hooks, ref as a prop and metadata all work in a plain client app built with Vite. Server Components and Server Functions need a framework that supports them, such as Next.js.