Introduction

React 19, the latest version of the popular JavaScript library for building user interfaces, was officially released on December 5, 2024. This release brings a host of new features, improvements, and optimizations aimed at enhancing the developer experience and improving web app performance. Whether you’re a seasoned React developer or just starting, there’s something in React 19 for everyone.

Key Features of React 19

  1. New Hooks and APIs: React 19 introduces several new hooks and APIs that simplify state management and component lifecycle handling, making your code more concise and easier to maintain.
  2. React Server Components: This powerful new feature allows you to build modern, dynamic web applications with less client-side JavaScript, resulting in faster load times and improved performance.
  3. Full Support for Custom Elements: React 19 now fully supports custom elements, enabling seamless integration with web components and allowing for greater flexibility in your app architecture.
  4. Performance Improvements: Various under-the-hood optimizations have been made to enhance the performance of React applications, ensuring a smoother and more responsive user experience.
Stay tuned for more detailed insights into each of these features, along with code examples to help you get started with React 19.

React DOM: <form> Actions

React 19’s new <form> features for react-dom now include Actions, enabling developers to pass functions as the action and formAction props of <form>, <input>, and <button> elements. This integration allows for automatic form submission with Actions.
Upon a successful <form> Action, React will automatically reset the form for uncontrolled components. To manually reset the <form>, you can utilize the new requestFormReset React DOM API.

React DOM: New hook: useFormStatus

This new hook is awesome. Let’s say you have a form component, and several components nested in the form (for example, buttons and checkboxes).
In previous versions of React, if you wanted to disable checkboxes while the form was pending (right after the user submitted it), you would have to create a custom context, or pass props (e.g., a disabled prop) to your components that were children of the form. Now, with React 19, you can just use a useFormStatus hook:
import {useFormStatus} from 'react-dom';
function DesignButton() {

  const {pending} = useFormStatus();

  return <button type="submit" disabled={pending} />

}
useFormStatus reads the status of the parent <form> as if the form was a Context provider.

New API: use

React 19 introducing a new API to read resources in render: use For example, you can read a promise with use, and React will Suspend until the promise resolves:
import {use} from 'react';

function Comments({commentsPromise}) {
  // `use` will suspend until the promise resolves.
  const comments = use(commentsPromise);
  return comments.map(comment =>
{comment}
); } function Page({commentsPromise}) { // When `use` suspends in Comments, // this Suspense boundary will be shown. return (
<div>Loading...</div>
}>
)}

New hook: useOptimistic

"use client";

import { useOptimistic } from "react";
import { send } from "./actions";

export function Thread({ messages }) {
  const [optimisticMessages, addOptimisticMessage] = useOptimistic(
    messages,
    (state, newMessage) => [...state, { message: newMessage }],
  );

  const formAction = async (formData) => {
    const message = formData.get("message") as string;
    addOptimisticMessage(message);
    await send(message);
  };

  return (
    <div>
      {optimisticMessages.map((m, i) => (
        <div key={i}>{m.message}</div>
      ))}
      <form action={formAction}>
        <input type="text" name="message" />
        <button type="submit">Send</button>
      </form>
    </div>
  );
}
Another common UI pattern when performing a data mutation is to show the final state optimistically while the async request is underway. In React 19, we’re adding a new hook called useOptimistic to make this easier:

Server Components

Server Components allow pre-rendering components before bundling, in a separate environment from your client app or SSR server. They can run at build time on your CI server or for each request via a web server. React 19 includes all React Server Components features from the Canary channel. Libraries with Server Components can now target React 19 as a peer dependency with a react-server export condition for full-stack React frameworks.

Server Actions

Server Actions allow Client Components to call async functions on the server. When defined with the „use server” directive, the framework creates a server function reference and passes it to the Client Component. When called, React sends a request to the server to execute the function and returns the result. Note: There is no „use server” directive for Server Components; it is used only for Server Actions. Server Actions can be created in Server Components and passed as props to Client Components or imported directly. For more details, see the docs for React Server Actions.

ref as a prop

Starting in React 19, you can now access ref as a prop for function components:
function MyInput({placeholder, ref}) {
  return <input placeholder={placeholder} ref={ref} />
}

//...
<MyInput ref={ref} />

<Context> as a provider

In React 19, you can render as a provider instead of <Context.Provider>:
const ThemeContext = createContext('');

function App({children}) {
  return (
    <ThemeContext value="dark">
      {children}
    </ThemeContext>
  );  
}
In future versions we will deprecate .

Cleanup functions for refs

React 19 now support returning a cleanup function from ref callbacks:
<input
  ref={(ref) => {
    // ref created

    // NEW: return a cleanup function to reset
    // the ref when element is removed from DOM.
    return () => {
      // ref cleanup
    };
  }}
/>

Document Metadata Hoisting

In HTML, tags like <title>, <link>, and <meta> are typically placed in thesection of the document. However, in React, the component responsible for setting these metadata tags might be far from where theis rendered, or themight not be rendered at all. Previously, developers had to manually insert these elements using effects or libraries like react-helmet, especially when server rendering React applications. With React 19, document metadata tags can now be natively rendered within components. This is a straightforward yet highly useful update, as metadata in your components will be automatically hoisted to the document’ssection.
function BlogArticle({article}) {
  return (
    <article>
      <h1>{article.title}</h1>
      <title>{article.title}</title>
      <meta name="author" content="fireup.pro" />
      <meta name="description" content={article.description} />
      <meta name="keywords" content={article.keywords} />
      <p>
        Article content, one two three...
      </p>
    </article>
  );
}

Support for stylesheets

Stylesheets, whether external (<link rel="stylesheet">) or inline (<style>), need careful DOM positioning due to style precedence rules. This complexity often forces users to load all styles far from dependent components or use encapsulating style libraries. React 19 simplifies this with built-in support for stylesheets, integrating into Concurrent and Streaming Rendering. By specifying stylesheet precedence, React manages the insertion order and ensures external styles load before dependent content is revealed.
function ComponentOne() {
  return (
    <Suspense fallback="loading...">
      <link rel="stylesheet" href="foo" precedence="default" />
      <link rel="stylesheet" href="bar" precedence="high" />
      <article class="foo-class bar-class">
        {...}
      </article>
    </Suspense>
  )
}

function ComponentTwo() {
  return (
    <div>
      <p>{...}</p>
      <link rel="stylesheet" href="baz" precedence="default" />  <-- will be inserted between foo & bar
    </div>
  )
}

Support for preloading resources

Informing the browser about necessary resources as early as possible during the initial document load and client-side updates can significantly boost page performance. React 19 introduces several new APIs for efficient loading and preloading of browser resources, simplifying the process of creating fast and seamless user experiences without being hampered by slow resource loading.
import { prefetchDNS, preconnect, preload, preinit } from 'react-dom'
function MyComponent() {
  preinit('https://.../path/to/some/script.js', {as: 'script' }) // loads and executes this script eagerly
  preload('https://.../path/to/font.woff', { as: 'font' }) // preloads this font
  preload('https://.../path/to/stylesheet.css', { as: 'style' }) // preloads this stylesheet
  prefetchDNS('https://...') // when you may not actually request anything from this host
  preconnect('https://...') // when you will request something but aren't sure what
}
<!-- the above would result in the following DOM/HTML -->
<html>
  <head>
    <!-- links/scripts are prioritized by their utility to early loading, not call order -->
    <link rel="prefetch-dns" href="https://...">
    <link rel="preconnect" href="https://...">
    <link rel="preload" as="font" href="https://.../path/to/font.woff">
    <link rel="preload" as="style" href="https://.../path/to/stylesheet.css">
    <script async="" src="https://.../path/to/some/script.js"></script>
  </head>
  <body>
    ...
  </body>
</html>

Support for async scripts

In HTML, normal and deferred scripts load in document order, making deep component tree rendering challenging, while async scripts load in arbitrary order. React 19 enhances support for async scripts, allowing them to be rendered anywhere in the component tree. This avoids the need to manage script relocation and deduplication. Async scripts are deduplicated across all rendering environments, ensuring they load and execute only once, even if rendered by multiple components. In Server Side Rendering, async scripts are included in theand prioritized behind critical resources like stylesheets, fonts, and image preloads. Those are just a few of the highlights! Other changes include:
  • New hook: useActionState
  • New React DOM Static APIs prerender , prerenderToNodeStream
  • Better error reporting
  • Support for Custom Elements
  • Diffs for hydration errors
  • Compatibility with third-party scripts and extensions