Skip to main content

.autoDispose

A common use case is to destroy the state of a provider when it is no-longer used.

There are multiple reasons for doing so, 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 come with built-in support for this 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.keepAlive

Marking a provider with autoDispose also adds an extra method on ref: keepAlive.

The keep function is used to tell Riverpod that the state of the provider should be preserved even if no longer listened to.

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 httpClient.get(...);
ref.keepAlive();
return response;
});

This way, if the request failed and the UI leaves the screen then re-enters it, then the request will be performed again. But if the request completed successfully, the state will be preserved and re-entering the screen will not trigger a new request.

Example: Canceling 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, cancel 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.keepAlive();
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 this, consider marking secondProvider with .autoDispose too:

final firstProvider = Provider.autoDispose((ref) => 0);

final secondProvider = Provider.autoDispose((ref) {
ref.watch(firstProvider);
});