React 19 New Features: What Developers Need to Know
On this page
React 19 is the most significant release in years, and it changes how we think about data fetching, forms, and server-side rendering. Where earlier versions left a lot of boilerplate to the community, React 19 bakes common patterns directly into the framework. If you have been wrangling useEffect for every async call or hand-rolling form submission state, this release is going to feel like a breath of fresh air.
This guide walks through the features that matter most in day-to-day work, with practical advice on when to adopt each one.
Actions: A New Way to Handle Mutations
The headline feature of React 19 is Actions. An Action is simply an async function passed to React's new transition machinery so that pending state, errors, and optimistic updates are managed for you.
Before React 19, submitting a form meant juggling several pieces of state by hand:
function UpdateName() {
const [name, setName] = useState("");
const [isPending, setIsPending] = useState(false);
const [error, setError] = useState(null);
async function handleSubmit() {
setIsPending(true);
try {
await saveName(name);
} catch (err) {
setError(err);
} finally {
setIsPending(false);
}
}
}
With Actions and the new useActionState hook, that collapses dramatically:
function UpdateName() {
const [error, submitAction, isPending] = useActionState(
async (previousState, formData) => {
const error = await saveName(formData.get("name"));
if (error) return error;
redirect("/success");
return null;
},
null
);
return (
<form action={submitAction}>
<input type="text" name="name" />
<button disabled={isPending}>Update</button>
</form>
);
}
The <form action={...}> syntax is new. React manages the pending state, resets the form on success, and surfaces errors automatically. Practical advice: reach for useActionState whenever a component performs a mutation that needs pending/error UI. It removes the most repetitive code in most apps.
useFormStatus for Design Systems
Closely related is the useFormStatus hook. It lets a child component read the status of the parent <form> without prop drilling. This is a gift for design system authors who build reusable submit buttons:
import { useFormStatus } from "react-dom";
function SubmitButton() {
const { pending } = useFormStatus();
return <button disabled={pending}>Submit</button>;
}
The button knows whether the form is submitting without anyone passing it a prop. Drop it inside any <form> and it just works.
The use() Hook
React 19 introduces use, a new primitive for reading resources during render. Unlike other hooks, use can be called conditionally and inside loops, which makes it far more flexible.
The most common use is unwrapping a promise, which integrates with Suspense:
import { use } from "react";
function Comments({ commentsPromise }) {
const comments = use(commentsPromise);
return comments.map((c) => <p key={c.id}>{c.text}</p>);
}
You can also read context with it:
function Heading({ children }) {
if (children == null) return null;
const theme = use(ThemeContext); // conditional — not allowed with useContext
return <h1 style={{ color: theme.color }}>{children}</h1>;
}
Practical advice: don't create promises directly inside render and pass them to use from the same component — they will be recreated on every render. Create them in a Server Component or a Suspense-enabled framework cache, then pass them down.
Server Components and Server Actions
React 19 marks the stabilization of React Server Components (RSC). Server Components render ahead of time, on the server or at build time, and ship zero JavaScript for their own logic. They let you query a database or read a file directly in a component without an API layer.
Server Actions complement them by letting client components call server-side functions marked with the "use server" directive. This effectively gives you typed RPC without writing endpoints:
"use server";
export async function createPost(formData) {
const title = formData.get("title");
await db.posts.insert({ title });
}
Most teams will adopt these through a framework like Next.js rather than wiring them up manually, since RSC requires a bundler and server integration. If you are on plain client-side React, you can still use everything else in React 19 without touching Server Components.
Improved Ref Handling: ref as a Prop
A small but beloved change: function components can now receive ref as a regular prop. forwardRef is no longer required.
function MyInput({ placeholder, ref }) {
return <input placeholder={placeholder} ref={ref} />;
}
// usage
<MyInput ref={inputRef} placeholder="Type here" />
forwardRef still works, but it is now deprecated and a codemod will eventually be available to migrate. New components should accept ref directly.
Refs also support cleanup functions now. A ref callback can return a function that runs when the element is removed, mirroring useEffect semantics.
Native Document Metadata
You can now render <title>, <meta>, and <link> tags anywhere in your component tree, and React will automatically hoist them into the document <head>:
function BlogPost({ post }) {
return (
<article>
<title>{post.title}</title>
<meta name="description" content={post.summary} />
<h1>{post.title}</h1>
</article>
);
}
This removes the need for libraries like React Helmet in many cases, and it works correctly with streaming SSR. Stylesheets and async scripts gained similar first-class support, including precedence ordering for stylesheets.
Better Error Messages and Hydration
React 19 improves hydration error reporting significantly. Instead of a generic warning, you get a clear diff showing what the server rendered versus the client. Errors are no longer logged twice, and onCaughtError / onUncaughtError root options give you finer control over error reporting.
Migration Tips
- Upgrade incrementally. First move to React 18.3, which adds deprecation warnings without behavior changes, then jump to 19.
- Run the codemods. The React team ships codemods (
npx codemod react/19/migration-recipe) that handle most mechanical changes. - Watch removed APIs.
propTypes,defaultPropson function components, legacy context (contextTypes), and string refs are gone. Audit older code for these. - Adopt features gradually. You don't have to rewrite everything. Start by replacing manual form state with
useActionStatein new code.
FAQ
Is React 19 a breaking release? It contains breaking changes, but most apps using modern patterns upgrade smoothly. The biggest removals affect legacy APIs that were deprecated years ago. Test thoroughly and lean on the official codemods.
Do I need a framework to use React 19?
No. Actions, use, useActionState, useFormStatus, ref-as-prop, and metadata support all work in plain client-side React. Only Server Components and Server Actions require framework or bundler integration.
Should I rewrite all my forms to use Actions? Not urgently. Existing forms keep working. Adopt Actions for new forms and migrate high-traffic ones when convenient — the payoff is less boilerplate and more reliable pending/error states.
What happens to forwardRef?
It still works but is deprecated. You can pass ref as a normal prop to function components now. Migrate when you touch a component; there's no rush.
Does the use() hook replace useEffect for data fetching?
For fetching that should suspend, use plus Suspense is the recommended pattern, especially with Server Components. useEffect is still appropriate for genuine side effects like subscriptions, event listeners, and syncing with non-React systems.
Is React 19 production-ready? Yes. The release is stable, and major frameworks already support it. As with any major upgrade, validate against your test suite and staging environment before shipping.
Final Thoughts
React 19 is about removing friction. The patterns you have been assembling by hand — pending flags, error state, metadata management, ref forwarding — are now part of the framework. Start small: introduce useActionState and ref-as-prop in new code, explore the use hook for data fetching, and consider Server Components when your framework supports them. Each feature stands on its own, so you can adopt them at a pace that fits your team.