MutationBuilder
The MutationBuilder handles data updates (CRUD) in your app. Unlike queries, mutations are not cached but can trigger cache invalidations or updates.
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'), ), ], ); },)Parameters
Section titled “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
Section titled “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
Section titled “Examples”Optimistic Updates
Section titled “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
Section titled “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'), ); },)