К содержимому

.autoDispose

Довольно часто есть необходимость аннулировать состояние провайдера, когда он больше не используется.

Существует множество причин, почему стоит так делать:

  • При работе с Firebase необходимо разрывать соединение и избегать лишних нагрузок.
  • Сбрасывать экран до начального состояния, когда пользователь переоткрыл его.

Провайдеры имеют встроенный механизм для этого: .autoDispose.

Использование

Чтобы Riverpod аннулировал состояние провайдера, когда он больше не используется, нужно просто добавить .autoDispose к нашему провайдеру:

final userProvider = StreamProvider.autoDispose<User>((ref) {

});

Готово. Теперь, когда userProvider перестанет использоваться, его состояние будет автоматически аннулировано.

Обратите внимание на то, что generic параметры указываются после autoDispose. autoDispose не является именованным конструктором.

примечание

Вы можете комбинировать .autoDispose с другими модификаторами, если вам это необходимо:

final userProvider = StreamProvider.autoDispose.family<User, String>((ref, id) {

});

ref.keepAlive

Использование autoDispose также предоставляет дополнительный метод для ref: keepAlive.

keepAlive сообщает Riverpod, что состояние провайдера должно быть сохранено, даже когда провайдер больше не используется.

Например, можно вызывать keepAlive после того, как завершился HTTP запрос:

final myProvider = FutureProvider.autoDispose((ref) async {
final response = await httpClient.get(...);
ref.keepAlive();
return response;
});

Таким образом, если запрос завершится неудачей, и пользователь переоткроет экран, то запрос будет снова осуществлен. Но, если запрос завершится успешно, тогда состояние будет сохранено, и переоткрытие экрана не спровоцирует новый запрос.

к сведению

В версии 1.0.x вместо keepAlive используется maintainState.

Пример: Отмена HTTP запросов, когда они больше не нужны

autoDispose можно использовать с FutureProvider и ref.onDispose, чтобы легко отменить HTTP запросы, когда они больше не нужны.

Цель:

  • Начать выполнение HTTP запроса, когда пользователь открыл экран
  • отменить запрос, если пользователь покинул экран до завершения запроса
  • если запрос успешно завершился, то покидание и переоткрытие экрана не должно спровоцировать новый запрос

В коде это может выглядеть так:

final myProvider = FutureProvider.autoDispose((ref) async {
// Объект из package:dio, который позволяет отменять http запросы
final cancelToken = CancelToken();
// Отменить http запрос при аннулировании провайдера
ref.onDispose(() => cancelToken.cancel());

// Получение данных и передача `cancelToken` в качестве аргумента
final response = await dio.get('path', cancelToken: cancelToken);
// Если запрос успешно завершился, сохранить состояние
ref.keepAlive();
return response;
});

The argument type 'AutoDisposeProvider' can't be assigned to the parameter type 'AlwaysAliveProviderBase'

При использовании .autoDispose вы можете оказаться в ситуации, когда приложение не компилируется, и появляется подобная ошибка:

The argument type 'AutoDisposeProvider' can't be assigned to the parameter type 'AlwaysAliveProviderBase'

Не волнуйтесь. Данная ошибка всего лишь погрешность. Это происходит, скорей всего, из-за следующего бага:

Вы пытаетесь слушать провайдер с .autoDispose внутри другого провайдера, который не использует .autoDispose, например:

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);
});

Так не стоит делать, потому что в этом случае firstProvider никогда не аннулируется.

Чтобы исправить это, просто используйте secondProvider с .autoDispose:

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

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