Riverpod AsyncValue持续加载并无限发起API请求问题求助
问题:Riverpod AsyncValue卡在加载状态且无限发起API请求
我正在使用带代码生成(code gen)的Riverpod框架,遇到了一个久未解决的问题:AsyncValue始终卡在加载状态,且代码会无限发起API请求。我是参照Riverpod仓库中的pub app示例进行开发的。
相关代码
Consumer Widget的build方法
@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(), ); }
fetchPostingBalancesProvider代码
@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); }
reportsRepositoryImplProvider代码
@riverpod ReportsRepositoryImpl reportsRepositoryImpl(ReportsRepositoryImplRef ref) => ReportsRepositoryImpl( dioState: ref.read(dioProvider), // a constant defined elsewhere );
API调用本身能正常执行,但组件始终卡在加载状态,请问该如何解决这个问题?
解决方案
1. 消除build方法中的不稳定参数
每次组件build时,你都会创建一个新的DateTimeRange实例。Riverpod会将这个对象作为provider的依赖,由于每次实例引用不同,会不断触发provider重新执行,导致无限API请求和加载状态循环。
解决方式:用StateProvider管理日期范围,确保参数实例稳定:
// 先定义一个StateProvider来管理日期范围 @riverpod DateTimeRange selectedDates(SelectedDatesRef ref) { return DateTimeRange( start: DateTime.now().subtract(const Duration(days: 5)), end: DateTime.now(), ); } // 修改build方法 @override Widget build(BuildContext context, WidgetRef ref) { final merchantId = hiveStorage.readString(key: StorageKey.merchantId)!; // 从StateProvider中读取稳定的日期范围实例 final selectedDates = ref.watch(selectedDatesProvider); final postingBalances = ref.watch( fetchPostingBalancesProvider( merchantId: merchantId, selectedDates: selectedDates, ), ); return postingBalances.when( data: (data) { // 用局部变量替代外部变量,避免不必要的状态变化 final 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(), ); }
2. 改用值类型参数替代引用类型
DateTimeRange是引用类型,默认的相等性判断是比较实例引用而非内容。如果不想用StateProvider,可以将参数拆分为单独的DateTime(值类型,相等性按时间值判断):
修改fetchPostingBalancesProvider:
@riverpod Future<PostingBalancesResponse?> fetchPostingBalances( FetchPostingBalancesRef ref, { required String merchantId, required DateTime startDate, required DateTime endDate, }) async { final cancelToken = ref.cancelToken(); return ref.watch(reportsRepositoryImplProvider).getPostingBalances( merchantId, DateTimeRange(start: startDate, end: endDate), cancelToken, ); }
修改build方法中的参数传递:
@override Widget build(BuildContext context, WidgetRef ref) { final merchantId = hiveStorage.readString(key: StorageKey.merchantId)!; // 定义稳定的日期值,DateTime是值类型,相同时间会被判定为相等 final startDate = DateTime.now().subtract(const Duration(days: 5)); final endDate = DateTime.now(); final postingBalances = ref.watch( fetchPostingBalancesProvider( merchantId: merchantId, startDate: startDate, endDate: endDate, ), ); // 后续when逻辑保持不变... }
3. 避免在data分支修改外部变量
原代码中postingBalancesList = data!...修改了外部变量,可能触发组件不必要的重新build,加剧循环问题。改用局部变量存储数据即可。
内容的提问来源于stack exchange,提问作者Yigit Kaya
相关产品推荐
相关产品推荐

