Skip to main content

Command Palette

Search for a command to run...

All the steps for Optimistic Updates in React Query

Updated
1 min read
All the steps for Optimistic Updates in React Query
T

Just a guy who loves to write code and watch anime.

The 6-Step Optimistic Update Pattern

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.