flutterflutter-providerriverpodriverpod-generator

Riverpod AsyncValue stuck at loading and constantly tries to make api call


I am trying Riverpod with code gen. I couldn't fix this for a while. when function stuck at loading and my code tries to make infinite API calls. I am following the example pub app at the riverpod repository.

my build method inside consumer widget,

@override
Widget build(BuildContext context, WidgetRef ref) {
final postingBalances = ref.watch(
  fetchPostingBalancesProvider(
    merchantId: hiveStorage.readString(key: StorageKey.merchantId)!,
    selectedDates: DateTimeRange(
      start: DateTime.now().subtract(
        const Duration(days: 5),
      ),
      end: DateTime.now(),
    ),
  ),
);

return postingBalances.when(
  data: (data) {
    postingBalancesList = data!.postingBalances!.items!;

    return Scaffold(
      appBar: AppBar(
        title: Text(tr.reports, style: TextStyles.title4),
        centerTitle: true,
      ),
      body: ListTile(
        title: Text(postingBalancesList.first.id),
        subtitle: Text(postingBalancesList.first.totalAmount.toString()),
      ),
    );
  },
  error: (err, stack) => Text('Error $err'),
  loading: () => const CircularProgressIndicator(),
);
}

fetchinPostBalancesProvider

@riverpod
Future<PostingBalancesResponse?> fetchPostingBalances(
FetchPostingBalancesRef ref, {
required String merchantId,
required DateTimeRange selectedDates,
}) async {
final cancelToken = ref.cancelToken();
return ref.watch(reportsRepositoryImplProvider).getPostingBalances(merchantId, 
selectedDates, cancelToken);
}

and reportsRepositoryProvider

@riverpod
ReportsRepositoryImpl reportsRepositoryImpl(ReportsRepositoryImplRef ref) => 
ReportsRepositoryImpl(
  dioState: ref.read(dioProvider), // a constant defined elsewhere
);

api calls works fine but my widgets get stuck at loading. How should i approach this anyone can help me?


Solution

  • An update to the value exposed by fetchPostingBalancesProvider would trigger a rebuild on the widget. After that, the DateTime.now() will be called again. This makes the DateTimeRange always changes every time the widget rebuild, and make the fetch method getting called again.

    The solution is to use another strategy to pass date information to the provider. For example, if you're in a StatefulWidget you can just call DateTime.now() once in a state variable and use that as the argument to the provider. Or you can pass the only necessary date information to the provider (for example, pass only day, month, year). Notice that DateTime.now() will always update even for milliseconds change, which is why you have infinite API calls.