Askr
Routing & Data

Mutations and Invalidation

Use mutations and invalidation with the current published Askr packages.

  • @askrjs/askr/data0.0.59

How to use mutations and invalidation

Describe the write, the cache prefixes it affects, and whether successful writes invalidate those prefixes.

  1. Import the published @askrjs/askr/data entrypoint.
  2. Keep mutations and invalidation configuration next to the component, route, or server composition root that owns it.
  3. Handle pending, unavailable, cancellation, and failure states, then verify the production path.
import { createMutation } from '@askrjs/askr/data';

const renameProject = createMutation({
  action: ({ id, name }, { signal }) => api.projects.rename(id, name, { signal }),
  affects: ({ id }) => ['project:' + id, 'projects'],
  afterSuccess: 'invalidate',
});

await renameProject.execute({ id, name });

Create a mutation

createMutation(options) takes an action(input, { signal }) function that performs the write and returns the result. What comes back is a Mutation<TInput, TResult> with execute(input), abort(), and reset() methods, plus status fields you read directly rather than through a callback.

Write lifecycle

A mutation's status is always one of 'idle', 'pending', 'success', or 'error', and the pending/error/result fields line up with whichever status you're in — result is only populated once status is 'success', error only once it's 'error'. Calling reset() puts it back to idle, and abort() cancels an in-flight execute() via the signal passed into the action function.

Targeted invalidation

The affects(input, result) option on MutationOptions maps a completed write to the list of query key prefixes it should invalidate, so a successful mutation automatically triggers invalidate() on exactly the queries it touched rather than clearing the whole cache. For writes that happen outside a mutation entirely, invalidate(prefix, options) and queryScope().invalidate() are available directly, and invalidateOnInterval() covers periodic invalidation gated by options like visibleOnly or focusedOnly.

Optimistic UI

There's no dedicated optimistic-value API on MutationOptions — no optimisticData field to set. Optimistic UI is built by hand: keep local state for the value you're predicting, render it while mutation.status is 'pending', and reconcile or roll it back once status settles to 'success' or 'error'. The afterSuccess: 'invalidate' option can be paired with this to refetch the real data as soon as the write completes, replacing your optimistic guess with the server's actual response.