13

I need to get 1 field 1 time from Firebase Cloud Firestore. How do I accomplish this with providers outside of Widget build?

Below are my combined providers. appStartupProvider is a FutureProvider and I want to get the bool value from this 1 field in firestore. However, the await in appStartupProvider states "'await' applied to 'AsyncValue', which is not a '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;
});

Obviously missing some key knowledge here on combing providers and AsyncValue, but I'm trying to accomplish the situation stated on RiverPod Combining Providers page, where I see await is being used.

enter image description here

Zelf
  • 1,723
  • 2
  • 23
  • 40
  • Did you sort this out? I am currently learning flutter and I have the same issue with the riverpod providers. I would like to resolve the return value of the provider so I can use the value in another one but can't find out proper way to do it. – groo Mar 07 '21 at 17:07
  • @groo See my answer below. https://stackoverflow.com/a/66955043/7259858 – Alex Hartford Apr 05 '21 at 15:03

2 Answers2

24

The example in the documentation was incorrect at the time of your post. It has since been updated and is now correct.

This is how you could write it:

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;
});

Or:

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;
});
Alex Hartford
  • 5,110
  • 2
  • 19
  • 36
15

await usage is available via:

example

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);
});

It seems that at the moment the documentation contains incorrect code examples. issue

nail
  • 715
  • 7
  • 20