Blogs

React 19: Smarter State Management with useTransition, useAction, and useFormStatus

About a year ago

Introduction

Hey there!

This is Sumit So, Welcome to my space on the internet _ _ _

If you are a React Developer or use React in some form, then things are about to get easier for you because React 19 is on its way, coming with some magical solutions for problems that were previously solved by depending on third-party solutions, like server-side rendering, or remembering previous states, managing multiple states like errors, or pending states during an API call. But now, React has finally answered all these crucial questions.

And in this blog, we will talk about some really cool features.

How were states managed previously during an API call?

Traditionally, managing state during an API call in React involved a lot of manual work. Developers had to handle loading states, errors, and updates to the component state upon receiving a response. This often led to bloated components with repetitive code, as you had to track loading and error states explicitly and update them at the right times.

What React 19 is going to help with

React 19 introduces new hooks and features that simplify state management during API calls and other asynchronous operations. These include enhancements to how React handles asynchronous updates, making it easier to manage state without cluttering your components with extra logic for handling loading and error states.

useTransition

useTransition automatically handles the pending state for you, so you no longer need to manually manage this state using code like:

// don't need this part anymore
const [isPending, setIsPending] = useState<>(...)

The useTransition hook informs you about the status of the pending state during an API call. For example, checkout complete code : /src/App.tsx

const [isPending, startTransition] = useTransition();
const handleAddUser = () => {
  startTransition(async () => {
    if (!username) {
      alert("Username cannot be empty");
      return;
    }
    await fetch("http://localhost:3001/users", {
      method: "POST",
      body: JSON.stringify({ name: username }),
    });
  });
};
return (
  <div>
    <div>
      ...
      <button type="submit" onClick={handleAddUser} disabled={isPending}>
        Add User
      </button>
      ...
    </div>
  </div>
);

useActionState hook

useActionState is specifically designed for use within React DOM forms, allowing direct integration of asynchronous functions in the form component's action prop. This hook provides error handling, pending state tracking, and an action handler. useActionState accepts a function—the "Action"—and returns a wrapped Action that you can call within your form. For example, see how it's used in the following code snippet from 'src/App.tsx':

const [_error, submitAddUser, isPending] = useActionState(
  async (_prevState: any, form: FormData) => {
    if (!username) {
      alert("Username cannot be empty");
      return;
    }
    const res = await fetch("http://localhost:3001/users", {
      method: "POST",
      body: JSON.stringify({ name: form.get("name") }),
    });
    if (res.ok) {
      setUsername("");
    }
  },
  null
);

useFormStatus

useFormStatus is a valuable addition to React, as it enables any child component within a form to access the form's submission status, regardless of their location in the application. This feature is particularly useful for managing UI elements like buttons based on the form's state, enhancing user experience by preventing multiple submissions.

For instance, below is the Button component which utilizes useFormStatus. This component lives in the folder /components/@ui/button:

import React from "react";
import { useFormStatus } from "react-dom";
const Button = () = {
    const { pending } = useFormStatus();
    return (
        <button type="submit" disabled={pending}>Add User</button>
    );
}
export default Button;

React 19 makes significant strides in improving the development experience by abstracting common patterns into hooks, allowing developers to write cleaner and more efficient code. As these features roll out, adapting to them can greatly enhance your React applications, making them more maintainable and enjoyable to work on.