You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 15:47:39