React 19 useTransition() hook

In React 18

When a user wants to change their name, the process typically involves typing the new name into an input box and then clicking the submit button (which triggers an API call). After submitting, we receive a response. In this case, we need to manage the following manually using useState() hooks:

  1. Pending states

  2. Errors

  3. Optimistic updates

  4. Sequential requests

Let’s take a look at how this can be done in the example below.

import React, { useState } from 'react';

// Assuming the API call function looks like this
const updateNameApiCall = async (name) => {
  try {
    const response = await fetch('/update-name', {
      method: 'POST',
      body: JSON.stringify({ name }),
      headers: {
        'Content-Type': 'application/json',
      },
    });

    const data = await response.json();

    if (!response.ok) {
      throw new Error(data.error || 'An error occurred');
    }
    return null;
  } catch (error) {
    return error.message;
  }
};

export const UpdateName = () => {
  const [name, setName] = useState('');
  const [error, setError] = useState(null);
  const [isPending, setIsPending] = useState(false);

  const handleSubmit = async () => {
    setIsPending(true);
    setError(null);
    const error = await updateNameApiCall(name);
    setIsPending(false);

    if (error) {
      setError(error);
    }
    window.location.href = '/path'; // Redirect after successful submission
  };

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

In React 19,

  1. A React team member introduced a hook to manage pending states, errors, forms, and optimistic updates automatically.

  2. The hook is named useTransition().

useTransition()
This hook accepts an asynchronous function as an argument and returns two values:

  1. A pending state

  2. A startTransition function.

  3.   import React, { useState, useTransition } from 'react';
    
      // Simulating the API call function
      const updateName = async (name) => {
        try {
          // Simulate an API call (replace with your actual API call)
          const response = await fetch('/update-name', {
            method: 'POST',
            body: JSON.stringify({ name }),
            headers: {
              'Content-Type': 'application/json',
            },
          });
    
          const data = await response.json();
    
          if (!response.ok) {
            throw new Error(data.error || 'An error occurred');
          }
    
          return null; // No error means success
        } catch (error) {
          return error.message;
        }
      };
    
      export function NewUpdateName() {
        const [name, setName] = useState('');
        const [error, setError] = useState(null);
        const [isPending, startTransition] = useTransition();
    
        const handleSubmit = () => {
          startTransition(async () => {
            const error = await updateName(name);
            if (error) {
              setError(error); // Set error if any
              return;
            }
    
            // On success, redirect the user
            window.location.href = '/path'; // This will redirect to the desired path
          });
        };
    
        return (
          <div>
            <input
              value={name}
              onChange={(event) => setName(event.target.value)}
              disabled={isPending} // Disable the input while waiting for the transition
            />
            <button onClick={handleSubmit} disabled={isPending || !name}>
              Update
            </button>
            {error && <p>{error}</p>}
          </div>
        );
      }