Capítulo 26 de 80
useMutation wraps a create/update/delete side-effect with the same status-tracking model as queries, plus a callback lifecycle (onMutate/onError/onSuccess/onSettled) that runs whether triggered via mutate or mutateAsync.
isIdle/isPending/isError/isSuccess (mirrors query status, plus an explicit idle/reset state); error and data populate accordingly.mutate(variables) fires-and-forgets with callbacks; mutateAsync(variables) returns a Promise you can await/try/catch directly for composing side effects.reset(): clears a mutation's error/data back to idle — needed since, unlike queries, a mutation's result isn't automatically cleared between calls.onMutate(variables) fires before the request (return a value to use for rollback later); onError(error, variables, onMutateResult); onSuccess(data, variables, onMutateResult); onSettled(data, error, variables, onMutateResult) — always last, success or failure. Returning a Promise from a callback makes the next callback wait for it.useMutation itself always fire; the same callback names can also be passed to mutate(vars, { onSuccess, ... }) for one-off, call-site-specific side effects — hook-level callbacks fire first, then call-level ones, and call-level callbacks are skipped if the component unmounts before the mutation finishes.useMutation's own callbacks run for every mutate() call; callbacks passed directly to mutate() fire only once, for the last call, even if several mutate() calls are in flight — because each mutate() call resubscribes the mutation observer.retry. Mutations that fail due to being offline retry in original call order once reconnected.scope: { id } to force them to run serially — later ones queue with isPaused: true until earlier ones in the same scope finish.queryClient.setMutationDefaults(mutationKey, options) registers a mutation's config globally so it survives dehydration; combined with dehydrate/hydrate/resumePausedMutations(), offline-paused mutations can resume after an app restart — but only if a default mutationFn was registered, since functions can't be serialized to storage.mutate directly as an event handler if the mutation function reads the event — wrap it in a plain handler that calls event.preventDefault() synchronously first.const mutation = useMutation({ mutationFn: addTodo })
// Fire-and-forget with callbacks
mutation.mutate({ title: 'Do Laundry' })
// Promise-based, for composing with other async logic
try {
const todo = await mutation.mutateAsync({ title: 'Do Laundry' })
} catch (error) {
// handle
}
mutate vs. awaitable mutateAsync.mutateAsync when you need to await the result to drive further logic; use mutate for the common fire-and-forget-with-callbacks case.retry explicitly if transient failures should be tolerated.scope.id when they must not race each other (e.g. sequential edits to the same resource).onSuccess typically does.onMutate's rollback-context pattern.