RiverPod - How to await using FutureProvider on AsyncValue not in widget

4,395

Solution 1

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

Solution 2

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

Share:
4,395
Zelf
Author by

Zelf

Updated on December 28, 2022

Comments

  • Zelf
    Zelf 11 months

    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