Capítulo 60 de 116

Chapter 60: useOptimistic

Core Idea

useOptimistic(value, reducer?) shows a hoped-for result immediately while a real async Action is still in flight, then automatically reconciles back to the real value once the Action settles — the standard tool for "show the message as sent right away" UX.

Key Concepts

  • Signature: const [optimisticState, setOptimistic] = useOptimistic(value, reducer?). value is the real, confirmed state (e.g. from props). optimisticState equals value whenever nothing is pending; while an Action is pending, it reflects the optimistic guess instead.
  • Optional reducer(currentState, action): like a useReducer reducer, computes the next optimistic state from an action payload — if omitted, calling the setter with a new value directly replaces the optimistic state.
  • Automatic reconciliation: once the underlying async Action completes and value itself updates to reflect the real result, optimisticState snaps back to just tracking value — there's no manual "clear the optimistic flag" step.
  • Must be called with a pending Action in the same component/tree — this Hook is meant to be used alongside a transition-driven Action (useTransition/form action), not as a general "temporary override" mechanism disconnected from an actual async operation.
  • Failure handling is the caller's job: if the Action fails, the optimistic guess doesn't automatically show an error state — the surrounding code needs to catch the failure and update the real value/UI accordingly, at which point the optimistic state reconciles to reflect that failure.

Code Examples

function Thread({ messages, sendMessage }) {
  const [optimisticMessages, addOptimisticMessage] = useOptimistic(
    messages,
    (state, newMessage) => [...state, { text: newMessage, sending: true }]
  );

  async function formAction(formData) {
    addOptimisticMessage(formData.get('message'));
    await sendMessage(formData.get('message')); // real Action; messages prop updates on success
  }

  return optimisticMessages.map(m => <p key={m.text}>{m.text}{m.sending && ' (sending...)'}</p>);
}
  • What it demonstrates: a message appearing in the list instantly (marked as sending) before the real sendMessage Action confirms — optimisticMessages reconciles to the real messages prop once it does.

Key Takeaways

  1. This Hook only makes sense paired with a real async Action — it's not a general-purpose "temporary state" utility.
  2. On success, reconciliation to the real value is automatic; on failure, the calling code must handle showing/reverting the error state itself.
  3. The optional reducer lets the optimistic update be more than a flat replace — e.g. appending to a list, as in the message-sending example.

Connects To

  • Ch 48 (useActionState): another Actions-oriented Hook, for reducer-style state plus a pending flag.
  • Ch 65 (useTransition): the general Actions mechanism this Hook's optimistic updates are meant to accompany.