一起养成写作习惯!这是我参与「掘金日新计划 · 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);
});