[译][官方文档] 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 不再被监听一段指定时长后清除状态。


相关推荐
子榆.2 小时前
Flutter 与开源鸿蒙(OpenHarmony)深度集成实战:从零构建跨平台应用
flutter·开源·harmonyos
恋猫de小郭3 小时前
Flutter UI 设计库解耦重构进度,官方解答未来如何适配
android·前端·flutter
程序员大辉5 小时前
新人学习Flutter,如何搭建开发环境(附所有安装包)
学习·flutter
子榆.5 小时前
Flutter 与开源鸿蒙(OpenHarmony)性能调优实战:从启动速度到帧率优化的全链路指南
flutter·开源·harmonyos
子榆.5 小时前
Flutter 与开源鸿蒙(OpenHarmony)安全加固实战:防逆向、防调试、数据加密全攻略
flutter·开源·harmonyos
子榆.6 小时前
Flutter 与开源鸿蒙(OpenHarmony)深度集成实战(二):实现跨设备分布式数据同步
flutter·开源·harmonyos
子榆.6 小时前
Flutter 与开源鸿蒙(OpenHarmony)上架华为应用市场全流程指南:从合规检测到审核通过
flutter·华为·开源
恋猫de小郭6 小时前
八年开源,GSY 用五种技术开发了同一个 Github 客户端,这次轮到 AI + Compose
android·前端·flutter
梧桐ty17 小时前
解耦之道:鸿蒙+Flutter混合工程的微内核架构与模块化实战
flutter·华为·harmonyos
名字被你们想完了20 小时前
Flutter 实现一个容器内部元素可平移、缩放和旋转等功能(六)
flutter