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


相关推荐
早起的年轻人11 小时前
Flutter String 按 ,。分割
flutter
helloxmg21 小时前
鸿蒙harmonyos next flutter通信之MethodChannel获取设备信息
flutter
helloxmg21 小时前
鸿蒙harmonyos next flutter混合开发之开发package
flutter·华为·harmonyos
lqj_本人2 天前
flutter_鸿蒙next_Dart基础②List
flutter
lqj_本人2 天前
flutter_鸿蒙next_Dart基础①字符串
flutter
The_tuber_sadness2 天前
【Flutter】- 基础语法
flutter
helloxmg2 天前
鸿蒙harmonyos next flutter通信之BasicMessageChannel获取app版本号
flutter
linpengteng3 天前
使用 Flutter 开发数字钱包应用(Dompet App)
前端·flutter·firebase