AsyncNotifierProvider
AsyncNotifier is powerful. It allows handling complex state that has an asynchronous initialization phase or requires mutating operations and reloading.
AsyncNotifier combines the flexibility of Notifier with the asynchronous capabilities of FutureProvider. It manages states wrapped in anAsyncValue and handles background loading and data mutations.
When to Use AsyncNotifier
- Authentication state with login/logout operations
- Fetching and creating database records sequentially
- Refreshing or retrying data fetches manually
Basic Syntax
Create an AsyncNotifier using the generator:
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'todos.g.dart';
@riverpod
class Todos extends _$Todos {
@override
FutureOr<List<Todo>> build() async {
// Perform initial fetch
return await ref.watch(apiServiceProvider).fetchTodos();
}
Future<void> addTodo(Todo todo) async {
// Set state to loading while keeping previous data (optimistic/background update)
state = const AsyncValue.loading();
// Add todo via API, then replace state with new valid data
state = await AsyncValue.guard(() async {
final newTodo = await ref.read(apiServiceProvider).addTodo(todo);
final prevTodos = state.valueOrNull ?? [];
return [...prevTodos, newTodo];
});
}
}State Mutations with AsyncValue.guard
Notice the use of AsyncValue.guard above. This utility simplifies executing an asynchronous callback, catching errors, and automatically returning an AsyncData or AsyncError. It handles stack traces so you keep detailed error tracking.
Using AsyncNotifier in Widgets
Similar to FutureProvider, use the .when() method:
class TodoListWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
// Read the async value
final todosAsync = ref.watch(todosProvider);
return todosAsync.when(
data: (todos) => ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return ListTile(title: Text(todos[index].title));
},
),
loading: () => Center(child: CircularProgressIndicator()),
error: (error, stack) => Text('Error: $error'),
);
}
}