[译][官方文档] 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}');
      },
    );
  }
}

相关推荐
程序员Ctrl喵18 小时前
异步编程:Event Loop 与 Isolate 的深层博弈
开发语言·flutter
前端不太难20 小时前
Flutter 如何设计可长期维护的模块边界?
flutter
小蜜蜂嗡嗡21 小时前
flutter列表中实现置顶动画
flutter
始持21 小时前
第十二讲 风格与主题统一
前端·flutter
始持21 小时前
第十一讲 界面导航与路由管理
flutter·vibecoding
始持21 小时前
第十三讲 异步操作与异步构建
前端·flutter
新镜1 天前
【Flutter】 视频视频源横向、竖向问题
flutter
黄林晴1 天前
Compose Multiplatform 1.10 发布:统一 Preview、Navigation 3、Hot Reload 三箭齐发
android·flutter
Swift社区1 天前
Flutter 应该按功能拆,还是按技术层拆?
flutter
肠胃炎1 天前
树形选择器组件封装
前端·flutter