[译][官方文档] Flutter/Dart 状态管理库 Riverpod (十一)- 概要 - 清空缓存和响应状态清除

原文链接:Clearing cache and reacting to state disposal | Riverpod

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

译时版本: 2.4.9


之前翻译过 Riverpod 的官方文档,现在随着版本更新,官方文档又多了很多新内容,所以再补充翻译一下。

之前翻译过的内容,现在官方文档有中文了。
Flutter状态管理库Riverpod官方文档翻译汇总 - 掘金 (juejin.cn)


清空缓存和响应状态清除

迄今为止,已经看到了如何创建/更新一些状态。但是还没有讨论状态清除时发生的处理。

Riverpod 提供了多种方式和状态清除进行交互。从延迟状态的清除到析构的响应。

状态是何时消除的?如何修改消除时机?

使用代码生成器时,状态默认在 provider 不再被监听时消除。

当一个 listener (监听器)在全框架中不再有活跃的 listener 时会发生。这种情况发生时,状态就会被消除。

该行为可通过使用 keepAlive: true 关掉。

这样做是为了防止所有的 listener (监听器)被移除时状态被消除。

dart 复制代码
// 可在注解中指定 "keepAlive" 来禁用状态的自动清除
@Riverpod(keepAlive: true)
int example(ExampleRef ref) {
  return 0;
}

注意

启用/禁用自动清除不会因为状态在 provider 重计算时是否被消除受影响。

状态总是会在 provider 重计算时被消除。
警告

provider 接收参数时,建议启用自动清除。这是因为不这样做的话,每个参数绑定的状态都会被创建,可能会导致内存泄漏。

响应状态清除

在 Riverpod 中,有一些消除状态的内置方式:

  • provider 不再使用并且是 "自动清除" 模式(稍后详细说明)。这种情况下,所有 provider 关联的状态会被消除。
  • provider 进行了重计算,如使用 ref.watch 时。这种情况下,会清除前一个状态,创建新的状态。

上面两种情况下,可能在状态清除发生时想要执行一些业务逻辑。

可用 ref.onDispose 来实现。该方法会注册一个 listner (监听器),来监听状态被消除的时机。

例如,可能想用它来关闭任意活动中的 StreamController

dart 复制代码
@riverpod
Stream<int> example(ExampleRef ref) {
  final controller = StreamController<int>();

  // 当状态被消除时,关闭 StreamController 。
  ref.onDispose(controller.close);

  // TO-DO: 在 StreamController 中推送一些值
  return controller.stream;
}

警告

ref.onDispose 回调不一定会触发副作用。在 onDispose 中修改 provider 可能会导致未知行为。
信息

还有其它一些有用的生命周期如:

  • ref.onCancel 会在 provider 的最后一个 listener 被移除时调用。
  • ref.onResume 会在 onCancel 调用之后添加新的 listener 时调用。
    信息

ref.onDispose 想调用多少次就可以调用多少次。在 provider 中为每个可清除的对象都调用一次也没有关系。 忘记清除一些对象时,这种做法会使事情变得简单。

手动强制消除 provider ,使用 ref.invalidate

有时可能想要强制消除 provider 。可使用 ref.invalidate 实现,该方法可在其它 provider 中或组件中调用。

Using ref.invalidate will destroy the current provider state. There are then two possible outcomes:

使用 ref.invalidate 会破坏 provider 的当前状态。会有两种可能的后果:

  • 如果 provider 被监听了,会创建新的状态。
  • 如果 provider 没有被监听,provider 会被完全消除。
dart 复制代码
class MyWidget extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return ElevatedButton(
      onPressed: () {
        // 点击时,消除 provider 。
        ref.invalidate(someProvider);
      },
      child: const Text('dispose a provider'),
    );
  }
}

信息

使用 ref.invalidateSelf provider 也能使它们自身失效。尽管这种情况下,这总是会导致新的状态被创建。
提示

尝试使接收参数的 provider 失效时,可以使单个指定参数的绑定失效,也可以一次性使所有参数的绑定失效:

dart 复制代码
@riverpod
String label(LabelRef ref, String userName) {
  return 'Hello $userName';
}

// ...

void onTap() {
  // 使所有可能的参数的绑定失效。
  ref.invalidate(labelProvider);
  // 仅使指定的绑定失效
  ref.invalidate(labelProvider('John'));
}
rust 复制代码
## 用 `ref.keepAlive` 进行精细化处置

正如上面提到的,当自动清除可用时,状态会在 provider 完全没有被监听时被消除。

但是有可能想要针对此行为进行更多的控制。例如,可能想保持正常完成的网络请求的状态,但是不缓存失败的请求。

可在启用自动清除后,使用 `ref.keepAlive` 实现。使用该方法,可以决定*何时*停止状态的自动清除。

```dart
@riverpod
Future<String> example(ExampleRef ref) async {
  final response = await http.get(Uri.parse('https://example.com'));
  // 只在网络请求正常完成后 保持 provider 存活。
  // 如果请求失败(并抛出错误),之后当 provider 不再被监听时,状态就会被消除。
  ref.keepAlive();

  // 可如下使用 `link` 存储自动清除的行为:
  // link.close();

  return response.body;
}

注意

如果 provider 重新计算了,自动清除则会重新可用。

也可以使用 ref.keepAlive 的返回值来恢复自动清除。

示例:保持指定时长的状态可用

现在 Riverpod 还没提供将状态保持指定时长的内建方式。

但是使用目前看到的工具实现这种特性很简单并做到可复用。

使用 Timer + ref.keepAlive ,可将状态保持指定时长。

要复用此逻辑,可以在扩展方法中实现它:

dart 复制代码
extension CacheForExtension on AutoDisposeRef<Object?> {
  /// 保持 provider 存活指定[时长].
  void cacheFor(Duration duration) {
    // 立即阻止状态被消除。
    final link = keepAlive();
    // 在时长到期后,重新启用自动消除。
    final timer = Timer(duration, link.close);

    // 可选项: 当 provider 重新计算时(如使用 ref.watch ),取消计时中的计时器。
    onDispose(timer.cancel);
  }
}

然后,可以如下使用:

dart 复制代码
@riverpod
Future<Object> example(ExampleRef ref) async {
  /// 保持状态可用 5 分钟
  ref.cacheFor(const Duration(minutes: 5));

  return http.get(Uri.https('example.com'));
}

该业务逻辑也可根据需求进行修改。例如,可以使用 ref.onCancel/ref.onResume 只在 provider 不再被监听一段指定时长后清除状态。


相关推荐
小龙在山东8 小时前
Flutter常用Widget小部件
flutter
yangshuo12819 小时前
git安装flutter
git·flutter
Kevin Coding9 小时前
Flutter使用Flavor实现切换环境和多渠道打包
android·flutter·ios
字节全栈_BjO9 小时前
Flutter Raw Image Provider
flutter
字节全栈_rJF1 天前
Flutter Candies 一桶天下
前端·javascript·flutter
pengyu1 天前
系统化掌握 Dart 编程之异常处理(二):从防御到艺术的进阶之路
android·flutter·dart
字节全栈_ZKt2 天前
FIDL:Flutter与原生通讯的新姿势,不局限于基础数据类型
flutter
小龙在山东2 天前
Flutter开发环境配置
flutter
字节全栈_ZKt2 天前
微店的Flutter混合开发组件化与工程化架构
flutter·架构·蓝桥杯
恋猫de小郭4 天前
Flutter 新春第一弹,Dart 宏功能推进暂停,后续专注定制数据处理支持
android·java·flutter