Skip to Content

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

NameTypeRequiredDescription
mutationFnFuture<T> Function(V)Yesfunction that performs the desired action.
builderWidget Function(BuildContext, MutationState<T>, MutateFunction<V>)YesBuilds the UI. Provides the state and a function to trigger the mutation.
optionsMutationOptions<T, V>?NoCallbacks for success, error, and optimistic updates.

MutationState Properties

PropertyTypeDescription
dataT?The result of the mutation.
errorObject?The error if the mutation failed.
statusMutationStatusidle, loading, success, or error.
isLoadingboolTrue 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