@void-snippets/react
useMutations
create, update, and remove mutations with full TanStack Query results.
#What it does
Returns three mutation objects — create, update, and remove. When any of them succeeds or fails, TanStack Query automatically invalidates the cache for this resource, triggering a background refetch.
#Signature
typescript
contactHooks.useMutations(): {
create: UseMutationResult<Contact.Detail, Error, Contact.Apis.Create>;
update: UseMutationResult<Contact.Detail, Error, { _id: Contact.Id; payload: Contact.Apis.Update }>;
remove: UseMutationResult<Contact.Detail, Error, Contact.Id>;
}
removeis the name (notdelete) becausedeleteis a reserved JavaScript keyword.
#Each mutation object
| Field | Description |
|---|---|
mutate(variables) | Fire-and-forget. Errors are silently caught unless you pass onError. Good for delete buttons. |
mutateAsync(variables) | Returns a Promise. Use with await when you need to wait before navigating or closing a modal. |
isPending | true while the request is in flight. Use to disable and show a loading state on buttons. |
isSuccess | true after the last call completed successfully. |
isError | true after the last call threw. |
error | The Error from the last failure. |
data | The server response from the last success. |
reset() | Return to idle state — clears isSuccess, isError, error. |
#The key pattern — await before closing a modal
tsx
function ContactsPage() {
const modal = useModal<Contact.Base>();
const { create, update, remove } = contactHooks.useMutations();
const handleSave = async (formData: Contact.Apis.Create | Contact.Apis.Update) => {
try {
if (modal.data) {
await update.mutateAsync({ _id: modal.data._id, payload: formData as Contact.Apis.Update });
} else {
await create.mutateAsync(formData as Contact.Apis.Create);
}
// Only runs when the server responded successfully
modal.closeModal();
toast.success(modal.data ? 'Contact updated' : 'Contact created');
} catch (err) {
// Modal stays open — form fields are intact, user can fix and retry
toast.error(err instanceof Error ? err.message : 'Something went wrong');
}
};
return (
<>
<Button onClick={modal.openCreateModal}>+ New</Button>
{list.map(contact => (
<ContactRow
key={contact._id}
contact={contact}
onEdit={() => modal.openEditModal(contact)}
onDelete={() => remove.mutate(contact._id)} // fire-and-forget — list auto-refreshes
/>
))}
<ContactModal
open={modal.isOpen}
data={modal.data}
isSaving={create.isPending || update.isPending}
onSave={handleSave}
onClose={modal.closeModal}
/>
</>
);
}