patterntypescriptModerate
Optimistic UI Updates Must Be Rolled Back on Server Rejection
Viewed 0 times
optimistic UIrollbacktemp IDreal-timeserver rejectionpending statemutation
Problem
Optimistic UI applies changes instantly for responsiveness, but when the server rejects the operation (validation error, concurrent conflict), the UI is left in an incorrect state with no user feedback.
Solution
Assign a temporary ID to each optimistic update. Store the previous state. On server error, revert to the stored state and show an error. On success, replace the temp ID with the server-assigned ID.
type OptimisticItem = { id: string; optimistic?: boolean; text: string };
async function addItem(text: string) {
const tempId = `temp-${Date.now()}`;
const prevItems = [...items];
// Optimistic add
setItems(prev => [...prev, { id: tempId, text, optimistic: true }]);
try {
const created = await api.post('/items', { text });
// Replace temp item with real one
setItems(prev => prev.map(i => i.id === tempId ? created : i));
} catch (err) {
// Roll back
setItems(prevItems);
showError('Failed to add item. Please try again.');
}
}Why
Without rollback, failed optimistic updates leave ghost data in the UI. Users may try to interact with items that do not exist on the server, causing cascading errors.
Gotchas
- Use a stable temp ID scheme — avoid Math.random() which can collide; use crypto.randomUUID().
- Visually distinguish optimistic items (opacity, spinner) so users know the action is pending.
- In a list that re-renders frequently, ensure rollback does not cause flicker by batching state updates.
- React Query and SWR have built-in optimistic update + rollback APIs — prefer them over manual state.
Revisions (0)
No revisions yet.