react-call v2

Mutation flow

A composition hook that wires a Callable to an async action. Pending is tracked for you, and on failure the call stays open — the user retries without losing their input.

The pattern

A form dialog runs an async save. While the save is in flight, the submit button shows pending. On success, the dialog closes with the response. On failure, the dialog stays open so the user can retry without losing what they typed.

That is the entire shape of useMutationFlow. It lives in a subpath import (react-call/mutation-flow) so consumers who don't need it pay zero bytes.

click "Open Save dialog" to start

Where each piece lives

  • MutationFn is a prop on the Call. It runs the side effect and decides — by calling call.end(…) or not — whether the Call closes. It lives in caller scope, alongside your domain logic.
  • useMutationFlow lives in the Callable body. It wraps the MutationFn, tracks pending, and returns a Trigger you wire to your submit button.
  • Pending is local component state inside the Callable. Disable inputs against trigger.pending the same way you'd disable against any other piece of state.

Failure semantics

When the MutationFn throws, useMutationFlow clears pending — via the same .finally that tracks the in-flight state — and does nothing to the error itself: it propagates as an unhandled rejection. The lib doesn't own your error handling, so it won't silence, log, or re-route the throw. If the failure matters to your UX or telemetry, wrap the body of your MutationFn in try/catch.

The Call stays open not because the throw was caught, but because closing a Call requires an explicit call.end() — and a MutationFn that throws never reaches it. The user sees the dialog return to its idle state and can try again.