skip to Main Content

I am trying to implement a very basic loading state.
During initState, sending a post request with some parameters. And want to show a loading state on UI during I got a result (success, or failure)

I can not understand how to use build() method and AsyncLoading() together. Also the return type of the provider and build method.

This is the provider I am trying to use:
I think I am missing something very similar, however can not find any example of such a case that the build method take parameters.
If this was a get method, there is an example.

void initState() {
  super.initState();
  Future.microtask(
    () async => ref.watch(wOListProvider.notifier).getWoList(widget.woNumber),
  );
@riverpod
class WOList extends _$WOList {
  @override
  FutureOr<List<WorkOrder>?> build() async {
    return null;
  }

  List<WorkOrder> _woList = [];

  Future<void> getWoList(int woNumber) async {
    state = const AsyncLoading();
    final result = await woListRepo.getWoList(wo: woNumber);

    switch (result) {
      case Success():
        _woList = result.value.map((wo) => wo.toEntity()).toList();
        state = AsyncData(_woList);
      case Failure():
        state = AsyncError(
          result.exception.message,
          StackTrace.current,
        );
    }
  }

What is the best practice for such a usage?

when build method returns null, state is not AsyncLoading anymore, and loading state is lost.

2

Answers


  1. All you need to do is this:

    @override
    Widget build(BuildContext context) {
      ref.watch(wOListProvider);
      final AsyncValue<List<WorkOrder>?> wOListAsync =
        ref.watch(wOListProvider.notifier).getWoList(widget.woNumber);
    
      // + check for null or use List<WorkOrder> in the state
    
      return switch (wOListAsync) {
          AsyncData(:final value) => ListView(
              children: [
                for (final workOrder in value)
                  ListTile(
                    title: Text(workOrder.toString()),
                  ),
              ],
            ),
          AsyncError(:final error) => Text('Error: $error'),
          _ => const Center(child: CircularProgressIndicator()),
        };
      }
    }
    

    Or use when/map instead of switch expression to parse the AsyncValue state.


    Also, you should store the current list in your WOList state, and not as a separate variable. Moreover, use .family (just make an argument in the notifier’s build method) to receive this argument directly from the widget when watching.

    Login or Signup to reply.
  2. You could use FutureFamilyProvider to handle api calls with parameter.

    @riverpod
    FutureOr<List<WorkOrder>> woList(WoListRef ref, {required int woNumber}) async {
      final woListRepo = ref.watch(woListRepoProvider);
      final result = await woListRepo.getWoList(wo: woNumber);
      return result;
    }
    
    // Consume the provider
    Widget build(BuildContext context, WidgetRef ref) {
      final woList = ref.watch(woListProvider(woNumber: woNumber));
      return woList.when(
        data: ...,
        error: ...,
        loading: ...,
      );
    }
    

    You can visit the docs here.
    https://docs-v2.riverpod.dev/docs/essentials/passing_args

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search