# mut-optimistic-updates: Implement Optimistic Updates for Responsive UI ## Priority: HIGH ## Explanation Optimistic updates immediately reflect changes in the UI before the server confirms them, creating a snappy user experience. Implement them for user-initiated mutations where the expected outcome is predictable. ## Bad Example ```tsx // No optimistic update - UI waits for server response const mutation = useMutation({ mutationFn: toggleTodoComplete, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['todos'] }) }, }) // User clicks checkbox, waits 200-500ms for visual feedback ``` ## Good Example: Via Cache Manipulation ```tsx const mutation = useMutation({ mutationFn: toggleTodoComplete, onMutate: async (todoId) => { // 1. Cancel outgoing refetches to prevent overwriting optimistic update await queryClient.cancelQueries({ queryKey: ['todos'] }) // 2. Snapshot previous value for potential rollback const previousTodos = queryClient.getQueryData(['todos']) // 3. Optimistically update the cache queryClient.setQueryData(['todos'], (old: Todo[]) => old.map((todo) => todo.id === todoId ? { ...todo, completed: !todo.completed } : todo ) ) // 4. Return context for rollback return { previousTodos } }, onError: (err, todoId, context) => { // Rollback on error queryClient.setQueryData(['todos'], context?.previousTodos) }, onSettled: () => { // Refetch to ensure consistency regardless of success/failure queryClient.invalidateQueries({ queryKey: ['todos'] }) }, }) ``` ## Good Example: Via UI Variables (Simpler) ```tsx // When mutation only affects local UI, use mutation state directly function TodoItem({ todo }: { todo: Todo }) { const mutation = useMutation({ mutationFn: toggleTodoComplete, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['todos'] }) }, }) // Show optimistic state while pending const displayCompleted = mutation.isPending ? !todo.completed // Optimistic: show toggled state : todo.completed // Settled: show actual state return (