Optimistic Update Pattern
Apply UI changes immediately before server confirmation with automatic rollback on failure.
import { useState, useCallback } from 'react';
interface UseOptimisticOpts<T> {
initialData: T;
onMutate: (data: T) => Promise<T>;
}
export function useOptimistic<T>({ initialData, onMutate }: UseOptimisticOpts<T>) {
const [data, setData] = useState<T>(initialData);
const [error, setError] = useState<string | null>(null);
const [pending, setPending] = useState(false);
const mutate = useCallback(
async (optimisticData: T) => {
const previous = data;
setData(optimisticData);
setError(null);
setPending(true);
try {
const confirmed = await onMutate(optimisticData);
setData(confirmed);
} catch (err) {
setData(previous);
setError(err instanceof Error ? err.message : 'Mutation failed');
} finally {
setPending(false);
}
},
[data, onMutate]
);
return { data, mutate, error, pending };
}
// Usage:
// const { data: likes, mutate } = useOptimistic({
// initialData: post.likes,
// onMutate: (count) => api.post(`/posts/${id}/like`, { count }),
// });
// <button onClick={() => mutate(likes + 1)}>{likes} Likes</button>Use Cases
- Like/upvote buttons
- Todo list toggling
- Real-time collaborative UIs
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
useLocalStorage — Persistent State Hook
Sync React state with localStorage including SSR safety, JSON serialization, and cross-tab updates.
usePrevious Hook
Track the previous value of any state or prop using a ref-based hook for comparison logic.
useFormValidation Hook
Lightweight form validation hook with field-level errors, touched tracking, and submit handling.
HTTP Client with Axios Interceptors
Pre-configured Axios instance with request/response interceptors for auth headers, logging, and retry logic.