Modern Web · React

React 19 New Features — A Complete Guide

A survey of what actually shipped in React 19: Actions, the use() hook, stable Server Components, ref as a regular prop, native document metadata, better hydration errors, and the Context shorthand.

John Kihiu12 min read

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.

TSX · use() with a promise
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.

forwardRef isn't gone, just usually unnecessary

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.

This is a survey, not a how-to

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.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.