Search code examples
flutterdartriverpod

correct use of AsyncNotifierProvider, AsyncNotifier - Riverpod


I can't seem to get my head around the correct use of AsyncNotifierProvider. Below code is not working right rn.

I have multiple AsyncNotifierProvider(lastTrialProvider & PendingProvider). How can I combine them and use(similar to Future.wait) single AsyncNotifierProvider(independentCardProvider).

Also, how do I call the independentCardProvider getCards method when my widget loads?

class IndependentCardListState extends ConsumerState<IndependentCardList> {
  @override
  Widget build(BuildContext context) { final viewModel = ref.watch(independentCardProvider); }
}

final independentCardProvider =
        AsyncNotifierProvider<IndependentCardProvider, List<EventModel>>(
            IndependentCardProvider.new);
    
class IndependentCardProvider extends AsyncNotifier<List<EventModel>> {
    
      IndependentCardProvider() : super() {
        getCards();
      }
    
      getCards() async {
        var pending = await ref.watch(pendingProvider);
        var last = await ref.watch(lastTrialProvider);
    
      // business logic here

        var sectionModel = EventModel();
        sectionModel.title = 'add';
        sectionModel.subTitle = 'add_to_schedule';
        
        state = AsyncValue.data([sectionModel]);
      }
    
      @override
      List<EventModel> build() {
        return [];
      }
    }

final pendingProvider =
    AsyncNotifierProvider<PendingProvider, List<Base>>(
        PendingProvider.new);

class PendingProvider extends AsyncNotifier<List<Base>> {
  final Repository repository = Repository();

  @override
  FutureOr<List<Base>> build() {

    return [];
  }

  getPending() async {
    state = await AsyncValue.guard(() async {
      FutureOr<List<Base>> trial = repository.getPending();
      return trial;
    });
  }
}

final lastTrialProvider =
    AsyncNotifierProvider<LastTrialProvider, Trial?>(
        LastTrialProvider.new);

class LastTrialProvider extends AsyncNotifier<Trial?> {
  final Repository repository = Repository();

  @override
  FutureOr<Trial?> build() {

    return null;
  }
}

Solution

  • When you use ref.watch on an AsyncNotifierProvider, it will give you an AsnycValue. To get a Future, you should watch for the future property of the provider instead.

    // `pending` is a `List<Base>` here
    var pending = await ref.watch(pendingProvider.future);
    

    You can then watch two providers in parallel with the Record.wait API to preserve the type of each.

    var (pending, last) = await (
      ref.watch(pendingProvider.future),
      ref.watch(lastTrialProvider.future),
    ).wait;
    

    Please note that with the new Notifier APIs, we should no longer put logic in the constructor body. Move the logic from the constructor to the build method:

    class IndependentCardProvider extends AsyncNotifier<List<EventModel>> {
    
      // REMOVE this constructor    
      IndependentCardProvider() : super() {
        getCards();
      }
    
      @override
      List<EventModel> build() {
        var (pending, last) = await (
          ref.watch(pendingProvider.future),
          ref.watch(lastTrialProvider.future),
        ).wait;
    
        // business logic here
    
        var sectionModel = EventModel();
        sectionModel.title = 'add';
        sectionModel.subTitle = 'add_to_schedule';
      }
    
        // ...
    }
    

    See also: