BloomMutation<T, P> class
Asynchronous mutation manager with automated optimistic updates, automatic rollback, and cache invalidation.
BloomMutation orchestrates side-effecting operations (such as HTTP POST, PUT, DELETE):
- Optimistic Updates: Immediately writes anticipated state changes into the BloomData cache via optimisticData before the network response completes.
- Automated Rollback: If the network call fails or throws, BloomMutation automatically reverts the cache entry at optimisticKey to its exact pre-mutation snapshot.
- Cache Invalidation: Automatically calls BloomData.invalidateQueries for all keys in invalidateKeys upon successful completion, triggering background refetches in active BloomQuery instances.
- Reactive Signals: Exposes data, status, and error as ReadonlySignal instances, allowing UI components to track loading and error states reactively.
Execution Flow
- status changes to MutationStatus.pending and error is cleared to
null. - If optimisticKey and optimisticData are set, snapshot current cache data and apply optimistic update.
- onMutate hook is executed; its returned value becomes the
context. - mutateFn is executed with the supplied parameters.
- On Success:
- data is set to the resolved result, status becomes MutationStatus.success.
- Cache queries in invalidateKeys are invalidated.
- onSuccess and onSettled hooks are awaited.
- On Error:
- error is set to the thrown exception, status becomes MutationStatus.error.
- If optimisticKey was modified, the cache is automatically rolled back to the pre-mutation snapshot.
- onError and onSettled hooks are awaited.
- mutateAsync rethrows the error, while mutate catches it and returns
null.
Backend Behavior
- Browser (
mount): SubscribedLivedescriptors update reactively across pending, success, and error states. - SSR (
renderToHtml): Safe to instantiate. Initial state is MutationStatus.idle.
Example
final createTodo = mutation<Todo, String>(
mutate: (title) => httpClient.post<Todo>('/todos', body: {'title': title}),
optimisticKey: ['todos'],
optimisticData: (title, oldTodos) => [
...?oldTodos as List<Todo>?,
Todo(id: 'temp-id', title: title, done: false),
],
invalidateKeys: [['todos']],
onError: (err, title, context) => print('Failed to add todo: $err'),
);
BloomNode buildAddTodoForm() {
return Div(
children: [
Button(
text: 'Create',
on: {'click': (e) => createTodo.mutate('Buy groceries')},
),
Live(() => createTodo.isPending ? Span(text: ' Saving...') : Span(text: '')),
],
);
}
See also:
- mutation, the convenience factory function for creating mutations.
- BloomQuery, for managing cached queries that this mutation invalidates.
- BloomData, the underlying cache manager.
Constructors
-
BloomMutation({required MutationFn<
T, P> mutateFn, List? optimisticKey, OptimisticUpdater<T, P> ? optimisticData, List<List> invalidateKeys = const [], OnMutateCallback<P> ? onMutate, OnSuccessCallback<T, P> ? onSuccess, OnErrorCallback<P> ? onError, OnSettledCallback<T, P> ? onSettled}) - Creates a BloomMutation instance with execution hooks and cache invalidation targets.
Properties
-
data
→ ReadonlySignal<
T?> -
Reactive signal holding the latest successful result data, or
nullif unexecuted or failed.no setter -
error
→ ReadonlySignal<
Object?> -
Reactive signal holding the unhandled exception thrown during execution, or
nullif idle/successful.no setter - hashCode → int
-
The hash code for this object.
no setterinherited
-
invalidateKeys
→ List<
List> -
List of query cache key prefixes invalidated upon successful mutation completion.
final
- isError → bool
-
Whether the mutation failed with an error (MutationStatus.error).
no setter
- isIdle → bool
-
Whether the mutation is in MutationStatus.idle status (unexecuted or reset).
no setter
- isPending → bool
-
Whether the mutation is actively in-flight (MutationStatus.pending).
no setter
- isSuccess → bool
-
Whether the mutation completed successfully (MutationStatus.success).
no setter
-
mutateFn
→ MutationFn<
T, P> -
The underlying asynchronous execution function performing the mutation.
final
-
onError
→ OnErrorCallback<
P> ? -
Optional hook invoked when the mutation fails with an error.
final
-
onMutate
→ OnMutateCallback<
P> ? -
Optional hook invoked immediately prior to executing the mutation.
final
-
onSettled
→ OnSettledCallback<
T, P> ? -
Optional hook invoked when the mutation settles (either success or error).
final
-
onSuccess
→ OnSuccessCallback<
T, P> ? -
Optional hook invoked upon successful mutation resolution.
final
-
optimisticData
→ OptimisticUpdater<
T, P> ? -
Optimistic data transformation callback applied to the cache before network resolution.
final
- optimisticKey → List?
-
Optional query cache key targeted for automated optimistic updates and rollback.
final
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
-
status
→ ReadonlySignal<
MutationStatus> -
Reactive signal indicating the current lifecycle MutationStatus (
idle,pending,success,error).no setter
Methods
-
mutate(
P params) → Future< T?> -
Safely executes the mutation with
params. -
mutateAsync(
P params) → Future< T> -
Executes the mutation with
params, returning the resolved data or rethrowing the caught error. -
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
reset(
) → void -
Resets the mutation state back to MutationStatus.idle, clearing data and error to
null. -
toString(
) → String -
A string representation of this object.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited