.autoDispose
A common use-case when using providers is to want to destroy the state of a provider when it is no-longer used.
There are multiple reasons for doing such, such as:
- When using Firebase, to close the connection and avoid unnecessary cost
- To reset the state when the user leaves a screen and re-enters it.
Providers comes with a built-in support for such use-case, through the .autoDispose
modifier.
Usage
To tell Riverpod to destroy the state of a provider when it is no-longer used,
simply append .autoDispose to your provider:
final userProvider = StreamProvider.autoDispose<User>((ref) {
});
That's it. Now, the state of userProvider will automatically be destroyed
when it is no-longer used.
Note how the generic parameters are passed after autoDispose instead of before –
autoDispose is not a named constructor.
note
You can combine .autoDispose with other modifiers if you need to:
final userProvider = StreamProvider.autoDispose.family<User, String>((ref, id) {
});
ref.maintainState
Marking a provider with autoDispose also adds an extra property on ref: maintainState.
The maintainState property is a boolean (false by default) that allows
the provider to tell Riverpod if the state of the provider should be preserved
even if no-longer listened.
A use-case would be to set this flag to true after an HTTP request have
completed:
final myProvider = FutureProvider.autoDispose((ref) async {
final response = await dio.get(...);
ref.maintainState = true;
return response;
});
This way, if the request failed and the user leaves the screen then re-enters it, then the request will be performed again. But if the request completed successfuly, the state will be preserved and re-entering the screen will not trigger a new request.
Example: Cancelling HTTP requests when no-longer used
The autoDispose modifier could be combined with FutureProvider and ref.onDispose
to easily cancel HTTP requests when they are no-longer needed.
The goal is:
- Start an HTTP request when the user enters a screen
- if the user leaves the screen before the request completed, cancels the HTTP request
- if the request succeeded, leaving and re-entering the screen does not start a new request
In code, this would be:
final myProvider = FutureProvider.autoDispose((ref) async {
// An object from package:dio that allows cancelling http requests
final cancelToken = CancelToken();
// When the provider is destroyed, cancel the http request
ref.onDispose(() => cancelToken.cancel());
// Fetch our data and pass our `cancelToken` for cancellation to work
final response = await dio.get('path', cancelToken: cancelToken);
// If the request completed successfully, keep the state
ref.maintainState = true;
return response;
});
The argument type 'AutoDisposeProvider' can't be assigned to the parameter type 'AlwaysAliveProviderBase'
When using .autoDispose, you may find yourself in a situation where your
application does not compile with an error similar to:
The argument type 'AutoDisposeProvider' can't be assigned to the parameter type 'AlwaysAliveProviderBase'
Don't worry! This error is voluntary. It happens because you most likely have a bug:
You tried to listen to a provider marked with .autoDispose in a provider that
is not marked with .autoDispose, such as:
final firstProvider = Provider.autoDispose((ref) => 0);
final secondProvider = Provider((ref) {
// The argument type 'AutoDisposeProvider<int>' can't be assigned to the
// parameter type 'AlwaysAliveProviderBase<Object, Null>'
ref.watch(firstProvider);
});
This is undesired, as it would cause firstProvider to never be disposed.
To fix, consider marking secondProvider with .autoDispose too:
final firstProvider = Provider.autoDispose((ref) => 0);
final secondProvider = Provider.autoDispose((ref) {
ref.watch(firstProvider);
});