The Complete Developer Guide to React 19, Part 1: Async Handling

No items found.

In short

React 19 beta introduces features aimed at enhancing state management, error handling, and async operations. While primarily for feedback from library developers, many features are stable. This first part of the guide focuses on new hooks like <rte-code>useTransition<rte-code> and <rte-code>useActionState<rte-code>, which streamline async handling, improve form management, and support optimistic updates for a better user experience.

Introduction

React 19 beta has been available on npm for some time now. While this release is currently intended for library developers and maintainers to gather feedback and improve the future stable version, most of its features can be considered stable.

These newly added features aim to assist application developers in their day-to-day tasks, which include state, error, and asynchronous handling. If used correctly, these updates should improve workflows, make applications faster, and simplify development.

This guide aims to review the most notable features, explain when they could be helpful, and explain how to use them with practical examples and short explanations. It comes in three parts—this is just the first part, focusing on Async Handling with Hooks. Part two delves into React 19 improvements and additions, while the last part explores upgraded resource support and presents overall conclusions:

Enhanced Async Handling with Hooks

Actions

Actions are intended to handle asynchronous requests and automate managing pending states, errors, and optimistic updates. Developers can handle async operations more intuitively now while keeping the UI responsive at all times - even when requests are happening live. 

Monitoring state with variables like <rte-code>isPending<rte-code> or <rte-code>isLoading<rte-code> during async operations can now be replaced with the new <rte-code>useTransition<rte-code> hook.

<rte-code>useTransition<rte-code> allows you to update the component state without blocking the user interface. In other words, it makes the application run and feel smoother while performing async operations in the background, like a network request.

One example of how to use the <rte-code>useTransition<rte-code> hook would be:

What's important to notice here:

  1. <rte-code>startTransition<rte-code> is content meaning that whatever is wrapped inside will not trigger a state update until all of the code inside is executed. In other words, no matter how many state updates are performed inside <rte-code>startTransition<rte-code> (in the example above only one - <rte-code>setError<rte-code>) all of them will come through as one update at the end. This makes the hook extremely useful as it would only cause one UI rerender instead of N rerenders where N is the number of state changes performed inside <rte-code>handleSubmit<rte-code>.
  2. Previously we would have to use an <rte-code>isPending<rte-code> state variable to detect whether <rte-code>updateName<rte-code> has been completed and the code for that would look something like this:
Notice that there might be a point where <rte-code>pending<rte-code> is set to <rte-code>false<rte-code>, but we don’t have the error just yet.

Now imagine if you had multiple async operations between <rte-code>setPending(false)<rte-code> and <rte-code>if(error)<rte-code> - as you can imagine it would not be a very nice user experience. This cannot happen in <rte-code>startTransition<rte-code> because it would produce only one state update at the end - after everything is completed. Moreover, it saves us one line of code!

  1. <rte-code>isPending<rte-code> will automatically be set to <rte-code>false<rte-code> after any transition which allows the developer to efficiently update the UI while the action is going and not have to worry about handling loading logic while the data is changing.
  2. Functions that use async transitions are called “Actions” by convention. Actions provide a pending state which automatically resets, supports optimistic updates, provides error handling to allow for Error Boundaries when a request fails and can also be passed to form <rte-code>action<rte-code> props.

Better handling form

React 19 also introduces a new hook called useActionState which provides developers with built-in support for handling form states and submission. This hook allows for the automatic management of pending states and results. 

Here are a few important things to notice:

  1. Everything inside <rte-code>useActionState<rte-code> is action code i.e. the code to be executed when the submit happens.
  2. <rte-code>formData<rte-code> is not really type-safe, meaning it’s not guaranteed that <rte-code>formData.get(name)<rte-code> will return text. A custom hook that uses <rte-code>useActionState<rte-code> with a validator could come in handy in order to validate data before passing it to API calls.
  3. <rte-code>submitAction<rte-code> is directly passed in the <rte-code><form /><rte-code> element action prop
  4. <rte-code>useActionState<rte-code> is specifically for actions and especially for forms

In addition to <rte-code>useActionState<rte-code> a new hook called <rte-code>useFormStatus<rte-code> has also been introduced to further simplify the usage of form elements in React 19. It allows developers to access form information in child components without having to drill down props or use context. The usage is straightforward and intuitive. 

<rte-code>useFormStatus<rte-code> provides access to four form properties: pending, data, method, and action

An important thing to note here is that only child components of the form element would be able to access these properties i.e. <rte-code>DesignButton<rte-code> is a child component of <rte-code><form /><rte-code> in this example.

Optimistic updates

Optimistic updates are a way of instantly showing the user the final state of the UI optimistically even though data mutations are ongoing in the background. The application feels more responsive this way and it’s especially helpful in cases of bad connection or services that take a long time to resolve. In case of an error, the UI is reverted to the original state.

In React 19 this functionality can be implemented using the new <rte-code>useOptimistic<rte-code> hook.

What's important here: 

  1. <rte-code>useOptimistic<rte-code> takes an initial value just like <rte-code>useState<rte-code>
  2. React will automatically revert <rte-code>optimisticName<rte-code> back to <rte-code>currentName<rte-code> when the submit finishes or errors.

New API use

React 19 introduces a way to read resources like promises and context in render using <rte-code>use<rte-code>. What is more, this new API can be used in conditionals as well which was previously uncharted territory for hooks. This change allows developers to manage data dependencies in a more effective way and focus on creating more dynamic and well-designed applications.

Reading a promise with <rte-code>use<rte-code> can be coupled with <rte-code>Suspense<rte-code> until the promise resolves, which is handy for network calls, for example:

An important thing to note here is that <rte-code>use<rte-code> does not support promises created in render. If you want to pass a promise, it must be cached or use a Suspense-compatible library or framework.

<rte-code>use<rte-code> can also be used for conditional rendering and to read from Context allowing for useful theme switching. Note that it cannot be called in a try-catch block, though.

An important thing to notice here is that there’s no need for context consumers and developers can just use <rte-code>use<rte-code> directly and obtain the context value even in conditional statements and early returns. Moreover, similar to <rte-code>useContext<rte-code>, <rte-code>use<rte-code> searches for the closest context provider that is above the component that calls it. This means that <rte-code>use<rte-code> does not consider context providers in the component from which it was called.

Server Components

React 19 introduces a way of rendering components ahead of time, either once at build time on a CI server or per each request using a web server. This happens in an environment separate from your client application called the “server”. If you have used Next.js before you might be familiar with the setup. 

With Server Components, React effectively allows developers to decide when the HTML file gets created—on a server, at build time, or at runtime, giving more flexibility and room for optimization.

Previously, a common way to read static data from a CMS, for example, would be to use an effect: 

With server components, this can be loaded at runtime, saving the client from having to download and parse 75K of libraries and wait for a second request to fetch the data after the page loads, just to render static content that will not change for the lifetime of the page.

Server Actions

This is a new functionality that allows client components to call async functions executed on the server. In other words, it is a binding between the server and the client. Defined with the ‘use server’ directive, these so-called Server Actions enable frameworks to automatically create a reference to the server function and pass that reference to the Client Component. 

Server Actions can be created in Server Components and passed as props to Client Components, or they can be imported and used in Client Components.

An important thing to note here is that ‘use server’ is not a directive you would put on top of a Server Component. Instead, it just creates a link between the server and the client. For example, putting ‘use client’ on top of a file informs React to send the JavaScript to the client where it can be used i.e. a tunnel from the server to send data to the client.

With ‘use server,’ it is the same but with the opposite direction - a tunnel on the server for the client to send data to. For example, to submit data with a form ‘use server’ would be used to let the server accept the form data from the client.

An example of a Server Component to add entries to a db would be:

When React renders the <rte-code>EmptyNote<rte-code> Server Component, it will create a reference to the <rte-code>createNoteAction<rte-code> function, and pass that reference to the Button Client Component. When the button is clicked, React will send a request to the server to execute the <rte-code>createNoteAction<rte-code> function with the reference provided:

In this example, the <rte-code>onClick<rte-code> Server Action is passed as a prop, but it could also be imported from a file:

Although these functionalities are different on their own, having access to both could be very handy for developers as it would improve reusability and modularity.

Other benefits of this new addition are improved SEO—more accessible content and enhanced performance—quicker initial page loads, especially for bigger applications that require a ton of resources and substantial content loads.

Now, let’s dive into the second part of the guide, where we’ll explore React 19’s improvements and additions, and the third part, where we talk about the upgraded support in React 19.

FAQ

No items found.
React Galaxy City
Get our newsletter

By subscribing to the newsletter, you give us consent to use your email address to deliver curated content. We will process your email address until you unsubscribe or otherwise object to the processing of your personal data for marketing purposes. You can unsubscribe or exercise other privacy rights at any time. For details, visit our Privacy Policy.

Callstack astronaut
Download our ebook

I agree to receive electronic communications By checking any of the boxes, you give us consent to use your email address for our direct marketing purposes, including the latest tech & biz updates. We will process your email address and names (if you have entered them into the above form) until you withdraw your consent to the processing of your names, or unsubscribe, or otherwise object to the processing of your personal data for marketing purposes. You can unsubscribe or exercise other privacy rights at any time. For details, visit our Privacy Policy.

By pressing the “Download” button, you give us consent to use your email address to send you a copy of the Ultimate Guide to React Native Optimization.