[官文翻译]Flutter状态管理库Riverpod - 概念 - 修饰符 .autoDispose

562 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情


Riverpod的官方文档有多国语言,但是没有汉语,所以个人简单翻译了一版。

官网文档:Riverpod

GitHub:GitHub - rrousselGit/river_pod

Pub:riverpod | Dart Package (flutter-io.cn)

译时版本:riverpod 1.0.3


.autoDispose

通常的使用场景是当 provider 不再被使用时销毁它的状态。

这样做有多种原因,比如:

  • 使用 Firebase 时,要关闭连接,避免不必要的成本。
  • 当用户离开一个界面然后重新进入时,重置状态。

provdier 通过 .autoDispose 修饰符内置对这种情况的支持。

用法

provider 不再被使用时,要告诉 Riverppod 来销毁状态,仅仅需要在 provider 后面添加 .autoDispose

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

});

就这样。现在 userProvider 的状态会在它不再被使用时自动销毁状态。

注意如何在 autoDispose 之后传递泛型参数代替之前的写法 - autoDispose 不是命名式的构造方法。

注意

如果需要,可以用其它修饰符绑定 .autoDispose :

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

});

ref.keepAlive

使用 autoDispose 标记 provider 也会在 ref 上添加额外的方法:keepAlive

keep 函数用来告诉 Riverpod 即使不再监听,provider 的状态也应该保持。

一个使用场景会是在 HTTP 请求完成后,将该标志设为 true

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

用这种方式,如果请求失败了并且 UI 离开了界面后重新进入,请求会再次运行。但是如果请求成功完成了,状态会被保持,再进入画面时不会触发新的请求。

例如: 不再使用时取消 HTTP 请求

autoDispose 修饰符可以用 FutureProvider 和 ref.onDispose 绑定, 当不再需要时可以方便地取消 HTTP 请求。

目标是:

  • 当用户进入一个画面时开始 HTTP 请求
  • 如果用户在请求完成前离开了画面,则取消 HTTP 请求
  • 如果请求成功了,离开画面再次进入时不会发起新的请求

在代码中,这会是:

final myProvider = FutureProvider.autoDispose((ref) async {
  // package:dio 包的对象允许取取消 HTTP 请求
  final cancelToken = CancelToken();
  // 当 provider 被销毁时,取消 HTTP 请求
  ref.onDispose(() => cancelToken.cancel());

  // 获取数据,传递我们的 `cancelToken` 用于取消能起作用
  final response = await dio.get('path', cancelToken: cancelToken);
  // 如果请求成功完成,则保持状
  ref.keepAlive();
  return response;
});

参数类型 'AutoDisposeProvider' 无法分配给参数类型 'AlwaysAliveProviderBase'

当使用 .autoDispose 时,你可能会发现自己陷入这样一种情况,就是你的应用无法编译,出现的错误类似于:

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

不用担心,该错误是自发的。它出现是因为很有可能有 BUG:

你可能尝试在没有标记为 .autoDispose 的 provider 中监听了标记为 .autoDispose 的 provider ,比如:

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 永远不会被释放。

要修复这个问题,考虑也用 .autoDispose 来标记 secondProvider

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

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