Capítulo 29 de 80

Chapter 29: Updates from Mutation Responses

Core Idea

When a mutation's response already contains the updated object, write it directly into the cache with setQueryData instead of invalidating and refetching — it's the same data, so the extra network call is pure waste; updates must always be applied immutably.

Key Concepts

  • Direct write over refetch: onSuccess: (data) => queryClient.setQueryData(['todo', {id: 5}], data) updates the matching query's cache entry with the mutation's own response, skipping a redundant refetch for data you already have.
  • Reusable pattern via custom hook: wrap the mutation + setQueryData pairing in a custom hook (e.g. useMutateTodo) so every call site gets the cache-sync behavior for free; the onSuccess callback's second argument (variables) is what the mutate() call was invoked with, useful for building the target key dynamically (['todo', { id: variables.id }]).
  • Immutability is mandatory: setQueryData's updater function must return a new object/array rather than mutating the oldData argument in place — in-place mutation can appear to work but causes subtle bugs (structural-sharing/reference-equality assumptions break silently).

Code Examples

const useMutateTodo = () => {
  const queryClient = useQueryClient()
  return useMutation({
    mutationFn: editTodo,
    onSuccess: (data, variables) => {
      queryClient.setQueryData(['todo', { id: variables.id }], data)
    },
  })
}

// Correct: immutable update
queryClient.setQueryData(['posts', { id }], (oldData) =>
  oldData ? { ...oldData, title: 'my new post title' } : oldData
)
  • What it demonstrates: a reusable mutation hook that syncs its own response into the cache, and the immutable-update shape setQueryData's updater function must follow.

Key Takeaways

  1. Prefer setQueryData from a mutation's response over invalidateQueries whenever the response already is the fresh data — it's strictly cheaper.
  2. Never mutate the oldData argument inside a setQueryData updater — always return a new object/array, even when just changing one field.
  3. Package this pattern into a custom hook once more than one component needs the same mutation + cache-sync behavior.

Connects To

  • Query Invalidation / Invalidations from Mutations: the refetch-based alternative this chapter's direct-write approach replaces.
  • Optimistic Updates: the next step — updating the cache before the response even arrives.