Optimistic Patterns with React Query and Zustand
Use React Query's onMutate/onError/onSettled callbacks and Zustand for structured optimistic UI workflows.
Optimistic Patterns with React Query and Zustand is a free React Academy lesson on CoddyKit — lesson 4 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.
React Query useMutation Overview
React Query's useMutation hook provides built-in infrastructure for optimistic updates through three lifecycle callbacks: onMutate (fires before the mutation, return a context object), onError (fires on failure, receives the context), and onSettled (fires on success or failure). This structure is designed specifically for optimistic patterns.
onMutate: The Optimistic Update Phase
In onMutate, you perform three steps: first, cancel any in-flight queries for the affected data (await queryClient.cancelQueries({ queryKey })), then snapshot the current cache (queryClient.getQueryData(queryKey)), and finally apply the optimistic update to the cache (queryClient.setQueryData(queryKey, updater)). Return the snapshot as context.
onError: Rolling Back with Context
The onError callback receives the error, the mutation variables, and the context returned from onMutate. Use the context to rollback: queryClient.setQueryData(queryKey, context.previousData). The context is the bridge between the snapshot taken in onMutate and the rollback in onError.
onSettled: Refetching for Sync
The onSettled callback fires regardless of success or failure. Use it to refetch the query and sync with server state: queryClient.invalidateQueries({ queryKey }). This ensures that after any mutation — whether it succeeded (the server may have transformed data) or failed (rollback complete) — you eventually converge on server truth.
React Query Optimistic Todo Toggle
A practical example: toggling a todo's completed state. In onMutate, snapshot the todos list, then update the specific todo in cache. In onError, restore the snapshot from context. In onSettled, invalidate the todos query to refetch. The user sees the toggle instantly; the server syncs in the background.
Zustand Optimistic Updates
In a Zustand store, optimistic updates are straightforward: create an action updateItem(id, changes) that immediately updates the item in the store, then calls the API. If the API fails, call another action revertItem(id, previousState). Zustand's synchronous state updates make the optimistic step instant.
Immer with Zustand for Complex Updates
When optimistically updating deeply nested Zustand state, use immer's produce for clean mutations: set(produce(state => { state.items[id] = { ...state.items[id], ...changes } })). Immer handles immutable updates with mutable syntax, making complex nested state changes readable and safe.
React 19 useOptimistic Hook
React 19 introduced useOptimistic(state, updateFn) as a built-in hook for optimistic updates within Server Actions. const [optimisticState, addOptimistic] = useOptimistic(items, (state, newItem) => [...state, newItem]). Calling addOptimistic(newItem) immediately updates the UI while the server action runs asynchronously.
useOptimistic Automatic Rollback
useOptimistic handles rollback automatically. When the Server Action completes (successfully or with an error), React reverts the optimistic state and applies the real state from the server. You do not need to write manual rollback logic — React manages the lifecycle of the optimistic update during the action's Suspense boundary.
Comparing the Three Approaches
Manual optimistic updates give full control but require boilerplate. React Query onMutate/onError/onSettled integrates with the query cache for automatic sync. useOptimistic is the simplest for Server Actions but requires React 19 and a server-action architecture. Choose based on your data layer: manual for simple local state, React Query for REST APIs, useOptimistic for RSC/Server Actions.
Choosing the Right Pattern
Consider your architecture when choosing an optimistic pattern. If you use React Query throughout your app, its onMutate pattern is consistent and cache-aware. If you use Zustand for global state, the action-based pattern fits naturally. If you are on React 19 with Server Actions, useOptimistic is the idiomatic choice. Mixing patterns within one app is common and acceptable.
React Query onMutate Return Value
What should the onMutate callback return in React Query to enable rollback in onError?
Lesson Recap: Optimistic Patterns
React Query useMutation uses onMutate (cancel queries, snapshot, apply optimistic update, return context), onError (restore snapshot from context), and onSettled (invalidate to refetch). Zustand optimistic updates call the state action immediately then the API, reverting on failure. React 19 useOptimistic provides automatic rollback within Server Actions. Choose the pattern that fits your data layer architecture.
Frequently asked questions
Is the “Optimistic Patterns with React Query and Zustand” lesson free?
Yes — the full text of “Optimistic Patterns with React Query and Zustand” 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 “Optimistic Patterns with React Query and Zustand”?
Use React Query's onMutate/onError/onSettled callbacks and Zustand for structured optimistic UI workflows. 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 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Optimistic Patterns with React Query and Zustand” 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
- What Is Optimistic UI and When to Use It
- Implementing Optimistic Updates Manually
- Rollback on Error and Conflict Resolution
- Optimistic Patterns with React Query and Zustand