typescriptadvanced

Optimistic Update Pattern

Apply UI changes immediately before server confirmation with automatic rollback on failure.

typescript
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.