Actions (experimental)
Actions are an imperative helper for running side-effects while temporarily keeping the providers used by that side-effect alive.
Actions are experimental, and the API may change in a breaking way without a major version bump.
They are designed for callbacks such as button presses, commands, tests, or
other event handlers where using watch would be inappropriate.
Riverpod exposes two top-level helpers:
action, which returns a value.voidAction, a shorthand for actions that returnvoid.
Running an action
Use an action from an imperative callback, then interact with providers through
read.
class AddTodoButton extends ConsumerWidget {
const AddTodoButton({super.key});
Widget build(BuildContext context, WidgetRef ref) {
return ElevatedButton(
onPressed: voidAction(() async {
await ref.read(todoListProvider.notifier).addTodo('Eat a cookie');
}),
child: const Text('Add todo'),
);
}
}
If you need a result, use action instead:
Future<Todo> createTodo(WidgetRef ref, String title) {
return action(() {
return ref.read(todoListProvider.notifier).addTodo(title);
});
}
Keeping providers alive
While an action is pending, providers read or listened to from inside its callback stay alive until the action completes.
This is especially useful with autoDispose providers:
final currentUserProvider = FutureProvider.autoDispose<User>((ref) {
return ref.read(apiProvider).fetchCurrentUser();
});
Future<User> loadCurrentUser(ProviderContainer container) {
return action(() async {
return await container.read(currentUserProvider.future);
});
}
Without the action wrapper, an imperative read like this may allow the provider to dispose as soon as the read is no longer actively listened to.
Supported APIs inside actions
Actions are meant to work with imperative APIs:
ProviderContainer.readRef.readWidgetRef.readProviderContainer.listenRef.listenWidgetRef.listenManual
Subscriptions created by those listen APIs are automatically closed when the action ends.
APIs to avoid inside actions
Actions are not declarative, so watch-based APIs are intentionally not part
of the pattern.
- Use
readinstead ofRef.watchorWidgetRef.watch. - Use
WidgetRef.listenManualinstead ofWidgetRef.listen.
If you need rebuilds driven by provider changes, stay in a declarative widget or provider context and use Consumers or
Refs APIs directly.Actions vs mutations
Use actions when you simply want to perform imperative work while keeping the used providers alive.
Use Mutations (experimental) when the user interface should also react to the pending, error, or success state of that side-effect.