MutationBuilder
The MutationBuilder handles data updates (CRUD) in your app. Unlike queries, mutations are not cached but can trigger cache invalidations or updates.
Usage
import 'package:fasq/fasq.dart';
MutationBuilder<Todo, String>(
mutationFn: (text) => api.addTodo(text),
options: MutationOptions(
onSuccess: (newTodo) {
// Invalidate the 'todos' query so it refetches
QueryClient().invalidateQuery('todos'.toQueryKey());
},
),
builder: (context, state, mutate) {
return Column(
children: [
if (state.hasError) Text('Error: ${state.error}'),
ElevatedButton(
// Pass data to the mutation
onPressed: () => mutate('New Todo Item'),
child: state.isLoading
? const CircularProgressIndicator()
: const Text('Add Todo'),
),
],
);
},
)API
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
mutationFn | Future<T> Function(V) | Yes | function that performs the desired action. |
builder | Widget Function(BuildContext, MutationState<T>, MutateFunction<V>) | Yes | Builds the UI. Provides the state and a function to trigger the mutation. |
options | MutationOptions<T, V>? | No | Callbacks for success, error, and optimistic updates. |
MutationState Properties
| Property | Type | Description |
|---|---|---|
data | T? | The result of the mutation. |
error | Object? | The error if the mutation failed. |
status | MutationStatus | idle, loading, success, or error. |
isLoading | bool | True while the mutation is running. |
Examples
Optimistic Updates
Update the UI before the server responds for a snappy experience.
MutationBuilder<Todo, Todo>(
mutationFn: (todo) => api.updateTodo(todo),
options: MutationOptions(
// Runs before the mutation function
onMutate: (newTodo, _) {
final client = QueryClient();
// 1. Cancel ongoing queries
client.cancelQuery('todos'.toQueryKey());
// 2. Snapshot previous value
final prevTodos = client.getQueryData('todos'.toQueryKey());
// 3. Optimistically update cache
client.setQueryData(
'todos'.toQueryKey(),
(old) => (old as List).map((t) => t.id == newTodo.id ? newTodo : t).toList()
);
// Return context to rollback if needed (optional)
return {'prevTodos': prevTodos};
},
onError: (err, newTodo, context) {
// Rollback on error
if (context != null) {
QueryClient().setQueryData('todos'.toQueryKey(), context['prevTodos']);
}
},
onSettled: (_, __, ___, ____) {
// Always refetch to ensure sync
QueryClient().invalidateQuery('todos'.toQueryKey());
}
),
builder: (context, state, mutate) {
// ...
}
)Form Submission with Side Effects
MutationBuilder<User, Map<String, dynamic>>(
mutationFn: (data) => api.createUser(data),
options: MutationOptions(
onSuccess: (user) {
Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Welcome ${user.name}!')),
);
},
),
builder: (context, state, mutate) {
return ElevatedButton(
onPressed: () {
if (formKey.currentState!.validate()) {
mutate({'name': nameController.text});
}
},
child: Text('Create Account'),
);
},
)Last updated on