# All the steps for Optimistic Updates in React Query

# The 6-Step Optimistic Update Pattern

```javascript
function useToggleTodo(id, sort) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: () => toggleTodo(id),
    onMutate: async () => {
      // 1. Cancel outgoing queries
      await queryClient.cancelQueries({
        queryKey: ['todos', 'list', { sort }]
      })

      // 2. Store previous state
      const snapshot = queryClient.getQueryData(['todos', 'list', { sort }])

      // 3. Set new optimistic state
      queryClient.setQueryData(
        ['todos', 'list', { sort }],
        (prev) => prev?.map(todo => 
          todo.id === id ? { ...todo, done: !todo.done } : todo
        )
      )

      // 4. Return rollback function
      return () => {
        queryClient.setQueryData(['todos', 'list', { sort }], snapshot)
      }
    },
    onError: (error, variables, rollback) => {
      // 5. Rollback if error
      rollback?.()
    },
    onSettled: () => {
      // 6. Invalidate to sync with server
      queryClient.invalidateQueries(['todos', 'list'])
    }
  })
}
```

# Why Each Step Matters

**Step 1 (Cancel)**: Prevents race conditions where a background refetch overwrites your optimistic update

**Steps 2-4 (Snapshot/Update/Return)**: Immediate UI feedback + rollback capability

**Step 5 (Rollback)**: If server says "nope", undo the optimistic change

**Step 6 (Invalidate)**: Even on success, double-check with server to stay in sync

# The Key Insight

The magic is in `onMutate` → it runs **before** the network request, so users see instant feedback. Then you handle the server response afterwards.
