React 19 is a bigger release than the version number suggests — it's less "one headline feature" and more a cleanup of several long-standing rough edges at once. This is the overview: what shipped, in one or two paragraphs each, with pointers to the deep-dive posts where I cover Actions, form actions, Server Components, and Strict Mode changes in more depth.
Actions and useActionState
Actions are async functions that React runs inside a transition, so a component gets pending/error state for free instead of hand-rolled useState triples. useActionState pairs an action with its latest result, and useFormStatus lets a nested component read a form's pending state without props passed down to it. I go into this in detail in the Actions and form actions posts — the short version is that mutations finally have a blessed pattern instead of everyone rolling their own.
The use() hook
use() reads the value of a promise or a context, and unlike other hooks it can be called conditionally — inside an if, after an early return, inside a loop. For promises, use() suspends the component until the promise resolves, which is how you read async data (typically produced in a Server Component) directly in a child without a useEffect and a loading-state dance.
import { use, Suspense } from 'react';
function Profile({ userPromise }: { userPromise: Promise<{ name: string }> }) {
const user = use(userPromise); // suspends until resolved
return {user.name}
;
}
export function ProfilePage({ userPromise }: { userPromise: Promise<{ name: string }> }) {
return (
Loading…}>
);
}
Server Components stabilize
React Server Components — components that render only on the server and ship no JS to the client — moved from experimental to a stable part of the React 19 release, with the conventions ("use client" boundaries, async server components) now considered production-ready rather than a canary-only feature. They're still a framework-level feature: you get them through Next.js's App Router or a similarly RSC-aware bundler, not by upgrading a plain Vite SPA to React 19.
ref as a prop, and <Context> as a provider
Function components can now accept ref as a plain prop, so simple ref-forwarding no longer needs forwardRef — you just declare function Input({ ref, ...props }) and pass it through. Similarly, a context object can now be rendered directly as <MyContext value={...}> instead of <MyContext.Provider value={...}>, which is a small shorthand but removes a bit of ceremony every context user used to write.
You'd still reach for forwardRef-style patterns for more advanced cases like imperative handles via useImperativeHandle. For the common "just pass the DOM ref through" case, a plain ref prop is enough now.
Document metadata, and better hydration errors
You can now render <title>, <meta>, and <link> tags directly inside any component, and React hoists them into <head> automatically — no more react-helmet for the basic case of a page setting its own title. Separately, hydration mismatch warnings in development got a real diff view showing exactly which DOM node and attribute disagreed between server and client output, instead of a wall of generic text that sent you guessing.
Each of these — Actions, Server Components, Strict Mode's new double-invocation behavior — has enough nuance to deserve its own post. This one is deliberately shallow so you can decide which to read next.
Wrapping up
None of React 19's changes are flashy on their own — a hook here, a shorthand there, a stabilized experiment — but together they remove a surprising amount of boilerplate that had accumulated over years of userland workarounds (react-helmet, forwardRef, hand-rolled pending state). If you're picking one thing to actually learn deeply first, make it Actions; it's the one that changes how you write everyday components, not just how you configure them.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.