DEV Community

Cover image for useTransition vs useOptimistic
Agbo, Daniel Onuoha
Agbo, Daniel Onuoha

Posted on

useTransition vs useOptimistic

I've distinguished between managing the loading state (useTransition) and faking the result (useOptimistic).

The Dynamic Duo: Managing Process vs. Managing Perception

To achieve the "illusion" of speed mentioned in your image, you need two distinct tools:

  1. useTransition: Handles the background work. It stops the browser from freezing and tells you if work is happening (isPending).
  2. useOptimistic: Handles the immediate visual feedback. It updates the UI instantly, assuming the background work will succeed.

The Scenario: A "Like" Button

Imagine a user clicks a "Like" button on a post.

  • Without Optimistic UI: The user clicks -> waits 1 second -> the number goes up. (Feels sluggish).
  • With Optimistic UI: The user clicks -> the number goes up instantly -> the server catches up in the background. (Feels snappy).

1. The "Standard" Approach (useTransition only)

Here, we rely on the server to tell us the new like count. We use useTransition only to show a loading spinner, so the user knows something is happening.

The Experience: User clicks → Spinner appears → Spinner vanishes & Number updates.

'use client';
import { useTransition } from 'react';
import { incrementLike } from './actions'; // Server Action

export default function StandardLikeButton({ likeCount }) {
  const [isPending, startTransition] = useTransition();

  const handleClick = () => {
    startTransition(async () => {
      // 1. We wait for the server to finish,
      await incrementLike(); 
      // 2. The UI will update only after the server responds and re-renders the page
    });
  };

  return (
    <button onClick={handleClick} disabled={isPending}>
      {/* We show a loading state because we don't have the new data yet */}
      {isPending ? "Updating..." : `♥ ${likeCount} Likes`}
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

2. The "Illusion" Approach (useTransition + useOptimistic)

Here, we predict the future. We know the user wants to add a like, so we visually add it immediately. We still use startTransition to keep the app responsive, but we don't wait for the server to update the number.

The Experience: User clicks → Number updates instantly. (No spinner needed).

'use client';
import { useOptimistic, useTransition } from 'react';
import { incrementLike } from './actions';

export default function OptimisticLikeButton({ likeCount }) {
  // Setup the Optimistic State
  // arg1: The real current data (from server)
  // arg2: A reducer function to calculate the "fake" new state
  const [optimisticLikes, addOptimisticLike] = useOptimistic(
    likeCount,
    (currentState, optimisticValue) => currentState + optimisticValue
  );

  const [isPending, startTransition] = useTransition();

  const handleClick = () => {
    startTransition(async () => {
      // 1. THE ILLUSION: Update the UI immediately
      addOptimisticLike(1); 

      // 2. THE REALITY: Perform the actual server request in the background
      // If this fails, React automatically rolls back the optimistic state!
      await incrementLike(); 
    });
  };

  return (
    <button onClick={handleClick}>
      {/* We display the optimistic (predicted) value immediately */}{optimisticLikes} Likes
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

Key Differences Summary

Feature useTransition useOptimistic
Primary Goal Prevents UI freezing; tracks "loading" status. shows the result instantly (before server confirms).
User Experience "Please wait..." (Honest delay) "Done!" (Instant gratification)
Data Source Waiting for Server Data. Uses Client-side prediction.
If Server Fails? App usually stays in the previous state or shows an error. Automatically reverts the UI to the correct server state.

Why use them together?

You rarely use useOptimistic without useTransition (or Server Actions which wrap transitions).

  • useOptimistic handles the data (showing 101 likes instead of 100).
  • useTransition handles the execution (making sure the button click doesn't freeze the page while the request travels to the server).

This combination creates the "speed and clean user experience".

Top comments (0)