如何用Riverpod 2.0发送POST请求并管理加载状态
问题:Riverpod中实现带参数POST请求的加载状态展示
需求:在组件initState阶段发送带参数的POST请求,请求过程中UI显示加载状态,成功/失败后展示对应内容。当前遇到的问题:
- 不清楚
build()方法如何与AsyncLoading配合使用 - 对Provider的
build方法返回类型存在疑问 - 当前代码中
build返回null导致加载状态丢失
用户尝试的代码:
组件初始化部分:
void initState() { super.initState(); Future.microtask( () async => ref.watch(wOListProvider.notifier).getWoList(widget.woNumber), ); }
Provider部分:
@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, ); } } }
最佳实践解决方案
1. 使用带参数的Family Provider
因为请求依赖woNumber参数,应该用Family类型Provider,直接将参数传递给build方法,让Riverpod自动管理异步状态,无需手动调用notifier方法。
2. 让build方法直接处理异步请求
将请求逻辑移到build方法中,Riverpod会自动将状态设为AsyncLoading,直到Future完成,解决加载状态丢失的问题。
3. 利用AsyncValue统一处理状态
通过AsyncValue的when方法,在UI层直接映射加载、成功、失败三种状态的UI。
修改后的代码示例
方式一:无状态的Future Provider(适合无需手动刷新的场景)
@riverpod FutureOr<List<WorkOrder>> woList(WoListRef ref, int woNumber) async { final result = await woListRepo.getWoList(wo: woNumber); switch (result) { case Success(): return result.value.map((wo) => wo.toEntity()).toList(); case Failure(): throw result.exception; // 抛出异常让AsyncValue自动处理错误状态 } }
方式二:Notifier Provider(适合需要手动刷新数据的场景)
@riverpod class WOList extends _$WOList { @override FutureOr<List<WorkOrder>> build(int woNumber) async { // 初始化时自动执行请求,状态自动进入AsyncLoading final result = await woListRepo.getWoList(wo: woNumber); switch (result) { case Success(): return result.value.map((wo) => wo.toEntity()).toList(); case Failure(): throw result.exception; } } // 手动刷新数据的方法 Future<void> refresh() async { // 强制重新执行build逻辑,自动进入加载状态 state = const AsyncLoading(); final currentWoNumber = ref.watch(this.select((state) => state.woNumber)); state = await AsyncValue.guard(() => build(currentWoNumber)); } }
UI层使用示例
@override Widget build(BuildContext context, WidgetRef ref) { // 监听带参数的Provider final woListAsync = ref.watch(woListProvider(widget.woNumber)); // 用when方法处理三种状态 return woListAsync.when( loading: () => const Center(child: CircularProgressIndicator()), error: (error, stackTrace) => Center(child: Text('加载失败:${error.toString()}')), data: (woList) => ListView.builder( itemCount: woList.length, itemBuilder: (context, index) { final workOrder = woList[index]; return ListTile(title: Text(workOrder.title)); }, ), ); }
关键说明
- 无需在
initState手动调用请求:当Widget监听带参数的Provider时,build方法会自动执行,发起请求,状态自动变为AsyncLoading。 - 避免手动维护状态:不需要额外的
_woList变量,状态直接由AsyncValue管理,更简洁可靠。 - 错误处理更规范:通过抛出异常让
AsyncValue自动生成AsyncError状态,无需手动构造。
内容的提问来源于stack exchange,提问作者Suat Özkaya
相关产品推荐
相关产品推荐

