Optimistic updates allow you to update the UI immediately when a user performs an action, before the server responds. This creates a snappy, responsive user experience.
Basic Pattern
Optimistic updates are implemented using the onMutate callback in mutations:
The Three Callbacks
onMutate
Runs before the mutation function. Use it to:
- Cancel outgoing queries
- Snapshot current data
- Optimistically update the cache
- Return context for rollback
onError
Runs if the mutation fails. Use the context to rollback:
onSettled
Runs after mutation completes (success or error). Refetch to sync with server:
Always invalidate in onSettled rather than onSuccess to ensure data is refreshed even after rollbacks.
Complete Example: Update Todo
Delete with Optimistic Update
Using queryOptions for Type Safety
Get better TypeScript support with queryOptions:
Updating Multiple Queries
Optimistically update related queries:
UI Feedback During Mutations
Show optimistic state in the UI:
Retry on Error
Show retry UI for failed optimistic updates:
Optimistic Updates with Infinite Queries
Update infinite query pages:
Always call cancelQueries before optimistic updates to prevent race conditions where a slow query overwrites your optimistic update.
Best Practices
- Always snapshot previous data in
onMutate for rollback
- Cancel queries before optimistic updates to avoid race conditions
- Use onSettled for invalidation, not
onSuccess (handles both success and error)
- Show visual feedback when mutations are pending
- Provide retry mechanisms for failed updates
- Test error scenarios thoroughly
Next Steps