Read mutation state from other components with useMutationState
When a component other than the one calling useMutation needs a mutation's status or pending variables, give the mutation a mutationKey and read it with useMutationState.
Implementation
- Set a
mutationKeyon mutations that other components observe, using the same hierarchical style as query keys, such as['todos', 'create']or['posts', postId, 'delete']. - Filter with
mutationKeyandstatus, and useselectto return only what the component renders. - Without
select, each result is the mutation's state object, with fields such asstatus,variables, andisPaused. - Use
mutation.mutationIdas a stable React key when rendering pending items. - Use
useIsMutatingwhen you only need a count. - The component calling
useMutationcan read its ownisPendingandvariablesdirectly.
Rationale
Mutation state lives in the query client's mutation cache, which any component under the provider can read. Threading it through props or a custom context couples distant components to the one that triggered the mutation and breaks when the trigger moves.
Examples
Incorrect (counterexample):
function TodoPage() {
const createTodo = useMutation({ mutationFn: api.createTodo });
return (
<>
<TodoForm onCreate={createTodo.mutate} />
<TodoList pendingTodo={createTodo.isPending ? createTodo.variables : undefined} />
</>
);
}
The page owns the mutation only so it can pass its state to a sibling.
Correct:
function TodoForm() {
const createTodo = useMutation({ mutationKey: ['todos', 'create'], mutationFn: api.createTodo });
// ...
}
function TodoList() {
const pendingTodos = useMutationState({
filters: { mutationKey: ['todos', 'create'], status: 'pending' },
select: (mutation) => ({ id: mutation.mutationId, todo: mutation.state.variables as NewTodo }),
});
return (
<ul>
{pendingTodos.map(({ id, todo }) => (
<PendingTodoItem key={id} todo={todo} />
))}
</ul>
);
}
Validation
Check that components showing another component's mutation progress read it through useMutationState or useIsMutating, and that the observed mutations have a mutationKey.
Reading isPending or variables in the component that calls useMutation is not a violation.