[译][官方文档] Flutter/Dart 状态管理库 Riverpod (九)- 概要 - WebSocket 和同步执行

原文链接:Websockets and synchronous execution | Riverpod

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

译时版本: 2.4.9


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

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


WebSocket 和同步执行

迄今为止,只说明了如何创建 Future

这是有意为之的,因为 Future 是 Riverpod 应用应当如何构建的核心。 不过,必要时,Riverpod 也支持其它格式。

特别是,除了 Future ,provider 还可自由用于:

  • 同步式返回对象,比如创建 "Repository" 。
  • 返回 Stream (流),比如监听 websocket 。

返回 Future 和返回 Stream 或对象总体上非常相似。 该篇可认为是用于这些场景的细微差别的说明和各种提示。

同步式返回对象

要同步式创建对象,要确保 provider 没有返回 Future :

dart 复制代码
@riverpod
int synchronousExample(SynchronousExampleRef ref) {
  return 0;
}

当 provider 同步式创建对象时,这会影响对象的消费方式。 特别是同步值不会封装在 "AsyncValue" 里面。

dart 复制代码
Consumer(
  builder: (context, ref, child) {
    // 该值不会封装在 "AsyncValue" 里面。
    int value = ref.watch(synchronousExampleProvider);

    return Text('$value');
  },
);

该差别的结果就是如果 provider 抛出了错误,尝试读取值会再次抛出错误。 作为替换方案,使用 ref.listen 时,"onError" 回调会被调用。

可监听对象的考量

可监听对象,如 ChangeNotifierStateNotifier 是不支持的。

如果,为了兼容性的原因,需要和该类对象进行交互,一个变通方案是将其通知机制移植到 Riverpod 。

csharp 复制代码
/// provider 创建了 ValueNotifier ,并且在值改变时更新它的 listener (监听器)。
@riverpod
ValueNotifier<int> myListenable(MyListenableRef ref) {
  final notifier = ValueNotifier(0);

  // provider 清理后对 notifier 进行清理。
  ref.onDispose(notifier.dispose);

  // ValueNotifier 更新时通知 provider 的 listener (监听器)。
  notifier.addListener(ref.notifyListeners);

  return notifier;
}

信息

万一需要多次该逻辑,那值得注意一下将逻辑共有! "ref" 对象是被设计成可组合的。这样将清理/监听逻辑放到 provider 之外:

csharp 复制代码
extension on Ref {
  // 可以移除 Ref 扩展前面的逻辑。
  // 这样可以在 provider 之间重用逻辑
  T disposeAndListenChangeNotifier<T extends ChangeNotifier>(T notifier) {
    onDispose(notifier.dispose);
    notifier.addListener(notifyListeners);
    // 返回 notifier 便于使用
    return notifier;
  }
}

@riverpod
ValueNotifier<int> myListenable(MyListenableRef ref) {
  return ref.disposeAndListenChangeNotifier(ValueNotifier(0));
}

@riverpod
ValueNotifier<int> anotherListenable(AnotherListenableRef ref) {
  return ref.disposeAndListenChangeNotifier(ValueNotifier(42));
}

监听 Stream (流)

现代应用的一个常见使用场景是和 websocket 交互,比如和 Firebase 交互或订阅 GraphQL 。

和这些 API 交互通常是通过监听 Stream (流)来完成。

为了助力此类需求,Rvierpod 天然支持 Stream (流)对象。如使用 Future ,对象会被转换成 AsyncValue

dart 复制代码
@riverpod
Stream<int> streamExample(StreamExampleRef ref) async* {
  // 每 1 秒钟生成 0 到 41 之间的一个数字。
  // 这可替换成源于 Firestore 或 GraphQL 的 Stream (流)或其它任何处理。
  for (var i = 0; i < 42; i++) {
    yield i;
    await Future<void>.delayed(const Duration(seconds: 1));
  }
}

class Consumer extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // Stream 流在这里被监听,并转换成了 AsyncValue 。
    AsyncValue<int> value = ref.watch(streamExampleProvider);

    // 可用 AsyncValue 处理加载中/错误状态和表示数据。
    return switch (value) {
      AsyncValue(:final error?) => Text('Error: $error'),
      AsyncValue(:final valueOrNull?) => Text('$valueOrNull'),
      _ => const CircularProgressIndicator(),
    };
  }
}

信息

Riverpod 没有考虑自定义 Stream (流)的实现,如 RX 的 BehaviorSubject 。因此,返回 BehaviorSubject 不会同步向组件暴露 value (值),即使在创建时已经可用。

禁用 Stream/FutureAsyncValue 的转换

Riverpod 默认会把 StreamFuture 转换为 AsyncValue 。 尽管不常用,但也可以禁用该行为,将返回类型封装到 Raw 的类型定义中即可禁用。

警告

通常不建议禁用 AsyncValue 的转换。只可在完全了解行为目的时这样做。

scala 复制代码
@riverpod
Raw<Stream<int>> rawStream(RawStreamRef ref) {
  // "Raw" 是一个类型定义。不需要将返回值封装在 "Raw" 构造函数中。
  return const Stream<int>.empty();
}

class Consumer extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 值不再会转换成 AsyncValue ,创建的 Stream (流)会原样返回。
    Stream<int> stream = ref.watch(rawStreamProvider);
    return StreamBuilder<int>(
      stream: stream,
      builder: (context, snapshot) {
        return Text('${snapshot.data}');
      },
    );
  }
}

相关推荐
火柴就是我2 小时前
flutter 之真手势冲突处理
android·flutter
Speed1232 小时前
`mockito` 的核心“打桩”规则
flutter·dart
法的空间3 小时前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
恋猫de小郭3 小时前
Android 将强制应用使用主题图标,你怎么看?
android·前端·flutter
玲珑Felone4 小时前
从flutter源码看其渲染机制
android·flutter
ALLIN1 天前
Flutter 三种方式实现页面切换后保持原页面状态
flutter
Dabei1 天前
Flutter 国际化
flutter
Dabei1 天前
Flutter MQTT 通信文档
flutter
Dabei1 天前
Flutter 中实现 TCP 通信
flutter
孤鸿玉1 天前
ios flutter_echarts 不在当前屏幕 白屏修复
flutter