0Pricing
React Academy · Lesson

Implementing Optimistic Updates Manually

Apply optimistic state locally, queue the mutation, and handle success and failure cases explicitly.

Implementing Optimistic Updates Manually is a free React Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the React Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

State Before the Mutation

Manual optimistic updates start with local component state initialized from server data: const [items, setItems] = useState(serverItems). This local state is what you render, and it is what you will mutate optimistically. You should NOT mutate server-fetched data directly — keep a local copy you control.

The Optimistic Update Step

When the user triggers a mutation (clicking "Add", "Like", "Delete"), perform the state update immediately before calling the API: setItems(prev => [...prev, newItem]). The UI reflects the change instantly. Only after this update do you fire the actual network request.

Capturing Previous State

Before making the optimistic update, capture the current state: const previousItems = items. This snapshot is your rollback target. If the API call fails, you restore this value. Store it in a variable (not state) since you only need it for the duration of the pending mutation.

Making the API Call

After the optimistic update, make the API call asynchronously. Wrap it in try/catch. On success, you can optionally refetch to sync with the server state, or trust the optimistic state if the server would return the same data. On failure, use the captured previous state to rollback.

Rollback on Failure

In the catch block of your mutation: setItems(previousItems). This restores the state to what it was before the optimistic update. Follow the rollback with an error notification. Users understand that rare failures happen — what they cannot tolerate is a silent inconsistency.

Showing Error Toast on Failure

After rolling back, display an error message: "Could not save changes. Please try again." with a Retry button that re-triggers the same mutation. This gives users agency. The combination of rollback + error toast + retry covers the failure case gracefully without blocking the entire UI.

The Temporary ID Problem

When adding a new item optimistically, the server has not yet assigned a real ID. Create a temporary ID for the optimistic item: const tempId = crypto.randomUUID(). Use this as the item's key in the list. After the API responds successfully, replace the temp ID with the server-assigned real ID.

Reconciling Temporary IDs

After a successful creation mutation, the server responds with the real ID. Update your state to replace the temporary item: setItems(prev => prev.map(item => item.id === tempId ? { ...item, id: serverResponse.id } : item)). This reconciliation ensures subsequent operations use the correct server ID.

The Race Condition Problem

If the user triggers two mutations in rapid succession, the responses may arrive out of order. The second mutation's response may arrive before the first, and the rollback of the first could overwrite the correct state from the second. This is a race condition unique to optimistic UI.

Serializing Mutations to Prevent Races

One solution to race conditions: serialize mutations using a queue. While a mutation is in-flight, disable the trigger button (setting isSubmitting state to true). Only allow the next mutation after the previous one completes. This sacrifices some responsiveness but guarantees correct state ordering.

Optimistic Delete Pattern

For delete operations: capture previous items, filter out the deleted item from state, call the delete API, and rollback on failure. Delete is simpler than create (no ID reconciliation) but the same principles apply. Consider adding a brief delay before the delete (showing an "undo" option) before making the API call.

Temporary ID in Optimistic Updates

Why do optimistically added items need a temporary ID?

Lesson Recap: Manual Optimistic Updates

The manual pattern: capture previousItems, setItems with the new state, make the API call, rollback on failure with setItems(previousItems) and show an error. For additions, use crypto.randomUUID() as a temp ID and reconcile with the server ID on success. Prevent race conditions by disabling the trigger during in-flight mutations. Rollback + toast + retry is the standard failure UX.

Frequently asked questions

Is the “Implementing Optimistic Updates Manually” lesson free?

Yes — the full text of “Implementing Optimistic Updates Manually” is free to read here on the web, and the React Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the React Academy course, upgrade to CoddyKit PRO.

What will I learn in “Implementing Optimistic Updates Manually”?

Apply optimistic state locally, queue the mutation, and handle success and failure cases explicitly. You practise React Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start React Academy?

No prior experience is required. React Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Implementing Optimistic Updates Manually” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this React Academy lesson?

Yes. Every React Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. What Is Optimistic UI and When to Use It
  2. Implementing Optimistic Updates Manually
  3. Rollback on Error and Conflict Resolution
  4. Optimistic Patterns with React Query and Zustand
← Back to React Academy