useApiMutation — React hook for mutations
TL;DR: useApiMutation(endpoint, options?) — a write hook (POST/PUT/DELETE/PATCH). It doesn't start
on its own; you run it via mutate (fire-and-forget) or mutateAsync (await + rethrows the error). On
success the endpoint's invalidatesTags auto-refetch the related useApiQuery.
A React hook over an ApiClient endpoint for writes (POST/PUT/DELETE/PATCH). Unlike
useApiQuery, the request does not start automatically — you trigger it with
mutate/mutateAsync. Mutations aren't cached (by REST method), and their invalidatesTags invalidate
the cache — active useApiQuery hooks of neighbouring endpoints refetch on their own via the
invalidation bus.
When to use it / when you don't need it
Use it for any write from a React component, when you want
isLoading/isErrorstates for a button and automatic invalidation of related queries after success.Not needed for reads (GET) — that's useApiQuery.
Not needed outside React or in effects — call
endpoint.request(...)directly (see ApiClient).
Import
import { useApiMutation } from 'synapse-storage/react'Usage
const endpoints = pokemonApiClient.getEndpoints()
function CreatePokemon() {
const { mutate, isLoading, isError, error } = useApiMutation(endpoints.createPokemon)
return (
<form
onSubmit={(e) => {
e.preventDefault()
mutate({ name: 'Pikachu' }) // fire-and-forget
}}
>
<button disabled={isLoading}>Create</button>
{isError && <Error message={error?.message} />}
</form>
)
}Return value
useApiMutation(endpoint, options?) returns:
| Field | Type | Description |
|---|---|---|
| mutate | (params) => void | Run the mutation; errors are not thrown (read error/isError) |
| mutateAsync | (params) => Promise<QueryResult> | Run and await; rejects on error |
| data | TData | undefined | Data of a successful response |
| error | Error | undefined | Mutation error |
| status | 'idle' | 'loading' | 'success' | 'error' | Current status |
| isLoading | boolean | status === 'loading' |
| isError | boolean | status === 'error' |
| isSuccess | boolean | status === 'success' |
| reset | () => void | Reset state back to idle |
options is the endpoint's QueryOptions (a mutation has no enabled/refetchOnInvalidate, since it's triggered manually):
useApiMutation(endpoints.createPokemon, {
timeout: 8000, // mutation timeout (ms)
signal: controller.signal, // external cancellation (the hook already cancels on unmount)
headers: new Headers(), // extra headers
context: { source: 'ui' }, // passed into baseQuery.prepareHeaders
retry: { count: 1 }, // retries for this mutation
// disableCache is irrelevant here: mutations are never cached anyway
})mutate vs mutateAsync
mutate(params)— fire-and-forget. The rejection is swallowed (state already reflects the error), so you don't need a.catch. Best for simple form submits.mutateAsync(params)— returns the promise and rethrows on error, so you canawaitand branch in flow:
Notes
StrictMode-safe. On unmount the in-flight request is aborted and state updates are skipped.
Mutations are never written to the cache (only GET is cached), so there's no
fromCachehere.
See also
useApiQuery — the companion hook for reads.
ApiClient — caching, tags and the invalidation bus.