RiverPod - 如何在不在小部件中的 AsyncValue 上等待使用 FutureProvider

Posted

技术标签:

【中文标题】RiverPod - 如何在不在小部件中的 AsyncValue 上等待使用 FutureProvider【英文标题】:RiverPod - How to await using FutureProvider on AsyncValue not in widget 【发布时间】:2021-05-30 08:08:19 【问题描述】:

我需要从 Firebase Cloud Firestore 获得 1 个字段 1 次。我如何使用 Widget 构建之外的提供者来实现这一点?

以下是我的综合提供商。 appStartupProvider 是一个 FutureProvider,我想从 firestore 的这个 1 字段中获取 bool 值。但是,appStartupProvider 中的 await 声明“'await' 应用于 'AsyncValue',这不是 'Future'”。

final accountStreamProvider = StreamProvider<Account>((ref) 
  final database = ref.watch(databaseProvider);
  return database != null ? database.accountStream() : const Stream.empty();
);

final _accountSetupCompleteProvider = Provider<AsyncValue<bool>>((ref) 
  return ref
      .watch(accountStreamProvider)
      .whenData((account) => account?.accountSetupComplete ?? false);
);

final appStartupProvider = FutureProvider<bool>((ref) async 
  final accountSetupComplete = await ref.watch(_accountSetupCompleteProvider);

  return accountSetupComplete;
);

这里显然缺少一些关于组合提供程序和 AsyncValue 的关键知识,但我正在尝试完成RiverPod Combining Providers 页面上所述的情况,我看到正在使用等待。

【问题讨论】:

你解决了吗?我目前正在学习颤振,并且与 Riverpod 提供商有同样的问题。我想解析提供者的返回值,以便可以在另一个提供者中使用该值,但找不到正确的方法。 @groo 请参阅下面的答案。 ***.com/a/66955043/7259858 【参考方案1】:

您发帖时文档中的示例不正确。它已经更新,现在是正确的。

你可以这样写:

final accountStreamProvider = StreamProvider<Account?>((ref) 
  final database = ref.watch(databaseProvider);
  return database != null ? database.accountStream() : const Stream.empty();
);

final _accountSetupCompleteProvider = FutureProvider<bool>((ref) async 
  final account = await ref.watch(accountStreamProvider.last);
  return account?.accountSetupComplete ?? false;
);

final appStartupProvider = FutureProvider<bool>((ref) async 
  final accountSetupComplete = await ref.watch(_accountSetupCompleteProvider.future);
  return accountSetupComplete;
);

或者:

final accountStreamProvider = StreamProvider<Account?>((ref) 
  final database = ref.watch(databaseProvider);
  return database != null ? database.accountStream() : const Stream.empty();
);

final _accountSetupCompleteProvider = Provider<AsyncValue<bool>>((ref) 
  return ref
      .watch(accountStreamProvider)
      .whenData((account) => account?.accountSetupComplete ?? false);
);

final appStartupProvider = Provider<bool>((ref) 
  final accountSetupComplete = ref.watch(_accountSetupCompleteProvider).maybeWhen(
        data: (data) => data, 
        orElse: () => false,
      );

  return accountSetupComplete;
);

【讨论】:

【参考方案2】:

await 的用法可通过以下方式获得:

.future FutureProvider documentation .lastStreamProviderdocumentation

例子

final carsListFutureProvider = FutureProvider<List<Car>>((ref) 
  final backend = ref.watch(backendProvider);
  return backend.getList(pathName, (json) => Car.fromJson(json));
);

final carFutureProvider = FutureProvider.family<Car?,int>((ref,id) async 
  final list = await ref.watch(carsListFutureProvider.future);
  return list.firstWhereOrNull((e) => e.id == id);
);

目前文档似乎包含不正确的代码示例。 issue

【讨论】:

以上是关于RiverPod - 如何在不在小部件中的 AsyncValue 上等待使用 FutureProvider的主要内容,如果未能解决你的问题,请参考以下文章

Flutter Riverpod 在没有上下文的情况下设置值

查找已停用小部件的祖先是不安全的 => 使用 Riverpod => 使用 "Navigator.of(context).pushReplacementNamed('/page'

使用 RiverPod 状态管理 Flutter 更改 Text 值

使用继承的小部件传递小部件键

如何编写我的小部件而不在 dojo.ready 中声明它的代码

每 5 秒更新一次文本小部件,而不在颤动中使用“setstate()”