Exploring What's New in React 19: Actions, Async Scripts, Server Components, and More

Dive into React 19's features like Actions for state management, async scripts support, server components, and enhanced error handling, revolutionizing modern web development.

ReactJS

ReactJS Update

React Compiler

Actions

Exploring What's New in React 19: Actions, Async Scripts, Server Components, and More

React 19 brings a plethora of exciting updates and functionalities, revolutionizing the way developers build modern web applications. In this article, we'll dive deep into the key features introduced in React 19, covering everything from Actions and Context Providers to improved error handling and support for async scripts.

Actions: Simplifying State Management

One of the most notable additions in React 19 is the introduction of Actions, which significantly simplifies state management and data mutation. Traditionally, handling pending states, errors, and sequential requests required manual intervention, leading to complex and error-prone code. However, with Actions, developers can streamline these processes, resulting in cleaner and more maintainable code.

For instance, let's consider a scenario where a user submits a form to update their name. In previous versions of React, managing pending states and errors required explicit handling using useState. However, with React 19's Actions, this process becomes much more straightforward and automated.

// Before Actions
function UpdateName({}) {
  const [name, setName] = useState("");
  const [error, setError] = useState(null);
  const [isPending, setIsPending] = useState(false);

  const handleSubmit = async () => {
    setIsPending(true);
    const error = await updateName(name);
    setIsPending(false);
    if (error) {
      setError(error);
      return;
    }
    redirect("/path");
  };

  return (
    <div>
      <input value={name} onChange={(event) => setName(event.target.value)} />
      <button onClick={handleSubmit} disabled={isPending}>
        Update
      </button>
      {error && <p>{error}</p>}
    </div>
  );
}

With the introduction of Actions, the same functionality can be achieved in a more concise and efficient manner:

// Using Actions for state management
function UpdateName({}) {
  const [name, setName] = useState("");
  const [error, setError] = useState(null);
  const [isPending, startTransition] = useTransition();

  const handleSubmit = async () => {
    startTransition(async () => {
      const error = await updateName(name);
      if (error) {
        setError(error);
        return;
      }
      redirect("/path");
    })
  };

  return (
    <div>
      <input value={name} onChange={(event) => setName(event.target.value)} />
      <button onClick={handleSubmit} disabled={isPending}>
        Update
      </button>
      {error && <p>{error}</p>}
    </div>
  );
}

The useTransition hook provided by React 19 simplifies the management of pending states and error handling, making the code more concise and readable.

Context Providers and Ref as a Prop

In addition to Actions, React 19 introduces improvements in Context Providers and supports accessing ref as a prop directly in function components. This simplifies the management of context providers and enhances the flexibility of function components.

// Rendering Context as a provider
const ThemeContext = createContext('');

function App({children}) {
  return (
    <ThemeContext value="dark">
      {children}
    </ThemeContext>
  );
}

// Ref as a prop in function components
function MyInput({placeholder, ref}) {
  return <input placeholder={placeholder} ref={ref} />
}

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

These enhancements not only improve developer productivity but also enhance the overall developer experience when working with React components.

Improved Error Handling

In React 19, error reporting and handling have seen significant improvements. Previously, errors in rendering caught by an Error Boundary would result in duplicate error throws and console logs. React 19 addresses this by logging a single error with comprehensive information, reducing clutter in error logs.

Moreover, React 19 introduces new root options for handling different types of errors, such as onCaughtError for errors caught by an Error Boundary, onUncaughtError for uncaught errors, and onRecoverableError for automatically recovered errors. These enhancements streamline error management and provide clearer insights into application errors.

These enhancements make it easier for developers to build robust and reliable applications using React.

Support for Stylesheets, Async Scripts, and Preloading Resources

React 19 also introduces support for stylesheets, async scripts, and preloading resources, improving performance and optimizing resource loading in React applications.

Example for Stylesheets

// Support for stylesheets
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>
  )
}

Example for Async Scripts

// async scripts
function MyComponent() {
  return (
    <div>
      <script async={true} src="..." />
      Hello World
    </div>
  )
}

function App() {
  <html>
    <body>
      <MyComponent>
      ...
      <MyComponent> // won't lead to duplicate script in the DOM
    </body>
  </html>
}

Example for Preloading resources

// Preloading resources

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>

These features enable developers to optimize their applications for better performance and user experience.

Compatibility with Third-Party Scripts and Extensions

In React 19, enhanced hydration to handle third-party scripts and browser extensions more effectively. Now, if an element rendered on the client doesn't match the server's HTML, React initiates a client re-render to correct it. Previously, such mismatches could lead to errors and additional renders.

What's new is that React 19 intelligently skips over unexpected tags in the and , preventing mismatch errors caused by these elements. Even when a full document re-render is necessary due to an unrelated hydration issue, React preserves stylesheets inserted by third-party scripts and extensions, ensuring smoother rendering and error handling.

This enhancement enhances the interoperability of React applications with external tools and libraries.

Support for Custom Elements

In React 19, custom elements receive comprehensive support, successfully passing all tests on Custom Elements Everywhere.

Previously, using Custom Elements in React posed challenges as React treated unknown props as attributes, not properties. React 19 introduces property support, operating smoothly on both client and server sides.

During Server Side Rendering, props of primitive types like string, number, or boolean true render as attributes. Non-primitive props like objects, symbols, functions, or false values are omitted. On the client side, props matching Custom Element properties are assigned as properties; otherwise, they become attributes. This enhancement streamlines custom element usage in React applications.

How to upgrade

See the React 19 Upgrade Guide for step-by-step instructions and a full list of breaking and notable changes.

Conclusion

In conclusion, React 19 introduces a wide range of enhancements and features that empower developers to build modern and efficient web applications. From streamlined state management with Actions to improved error handling and support for async scripts, React 19 elevates the development experience and sets new standards for building robust and reliable applications. Incorporating these features into your projects can lead to more scalable, maintainable, and performant React applications.


Get latest updates

I post blogs and videos on different topics on software
development. Subscribe newsletter to get notified.


You May Also Like

When to Use a Monorepo: Benefits, Drawbacks, and Practical Examples

When to Use a Monorepo: Benefits, Drawbacks, and Practical Examples

Learn when to use a monorepo, its benefits, and drawbacks. This guide includes practical examples to help you decide if a monorepo is right for your development projects.

NodeJS: An Introduction to Streams for Efficient Data Handling

NodeJS: An Introduction to Streams for Efficient Data Handling

Learn the basics of NodeJS streams, including reading, writing, and piping data, to efficiently handle large data sets in your applications with practical code examples.

Mastering API Rate Limiting in Node.js: Best Practices and Implementation Guide

Mastering API Rate Limiting in Node.js: Best Practices and Implementation Guide

Learn how to effectively implement API rate limiting in Node.js using express-rate-limit library. Explore factors to consider when setting rate limits for optimal API performance and user experience.