When users post a comment, like a post, or update a setting, traditional web applications show a loading spinner while waiting for the server response. This latency creates a sluggish experience.

Optimistic UI is a pattern where the application immediately updates the screen assuming the server operation will succeed. With **React 19**, Meta introduced the native useOptimistic hook to manage optimistic state seamlessly and roll back automatically if the background operation fails.

1. How `useOptimistic` Works

The useOptimistic hook takes two arguments: the current actual state, and an update function that merges optimistic changes. It returns a tuple containing the optimistic state and an optimistic dispatch function.

const [optimisticState, addOptimistic] = useOptimistic(
  currentState,
  (state, optimisticValue) => {
    // Return updated state combining current state and optimistic value
    return [...state, { ...optimisticValue, sending: true }];
  }
);

2. Real-World Code Example: Real-Time Chat Message List

Here is a practical example of a chat application using useOptimistic to display new messages instantly while sending them to the backend server:

import { useOptimistic, useState, useRef } from 'react';

export default function ChatApp({ messages, sendMessageAction }) {
  const formRef = useRef(null);

  // 1. Define optimistic state for messages
  const [optimisticMessages, addOptimisticMessage] = useOptimistic(
    messages,
    (state, newMessageText) => [
      ...state,
      { text: newMessageText, id: Date.now(), sending: true }
    ]
  );

  async function formAction(formData) {
    const text = formData.get('message');
    formRef.current.reset();

    // 2. Trigger instant UI update
    addOptimisticMessage(text);

    // 3. Perform background server action
    await sendMessageAction(text);
  }

  return (
    <div className="p-3 bg-light rounded">
      <ul className="list-group mb-3">
        {optimisticMessages.map((msg) => (
          <li key={msg.id} className="list-group-item d-flex justify-content-between align-items-center">
            {msg.text}
            {msg.sending && <span className="badge bg-warning text-dark">Sending...</span>}
          </li>
        ))}
      </ul>
      <form ref={formRef} action={formAction} className="d-flex gap-2">
        <input name="message" className="form-control" placeholder="Type a message..." required />
        <button type="submit" className="btn btn-danger">Send</button>
      </form>
    </div>
  );
}

3. Automatic Error Rollback & State Recovery

If the background server action fails or throws an exception, React automatically reverts optimisticMessages back to the true server state (messages). Developers don't need to write manual try/catch cleanup logic for state reversion!

4. Comparison Table

Pattern User Feedback Latency Implementation Complexity
Traditional Spinner High (waits 500ms - 2s for network) Low (standard isLoading boolean)
Manual Optimistic UI Zero (Instant) High (requires manual state rollbacks & error handling)
React 19 useOptimistic Zero (Instant) Low (Built-in state merging & auto rollback)
Learn Full-Stack React 19 Development

Master React 19 hooks, Server Actions, and Next.js App Router in Telugu IT Tutorials' online coding classes. Explore Courses →