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

Flutter Riverpod FutureProvider持续AsyncLoading,Dropdown联动API异常

问题描述

使用DropdownSearch组件实现三个下拉搜索框,初始通过单个API加载三个下拉框数据;需求是第一个下拉框选中项变更时,调用新API更新第二个下拉框数据,但实现后ledgerItemProvider始终处于AsyncLoading<Map<dynamic, dynamic>>状态,无法获取数据。

问题原因分析
  1. 参数硬编码未关联选中值:第二个下拉框的API请求参数(如listNameId里的35)是固定值,没有使用第一个下拉框的选中项,导致请求的不是对应分组的数据,甚至可能因参数错误导致后端无响应。
  2. Family Provider参数相等性问题:GetListModel未重写==和hashCode,Riverpod的Family Provider默认通过引用判断参数是否变化,每次重建都会生成新的GetListModel实例,可能导致不必要的重建或无法正确触发更新。
  3. Provider未配置自动清理:ledgerItemProvider未使用.autoDispose,可能存在内存泄漏,且状态管理不够严谨。
  4. API错误处理不严谨:LedgerProvider中请求失败时仅打印状态码,未抛出错误,导致Provider一直停留在Loading状态,无法进入Error状态暴露问题。
  5. 依赖未正确关联:第二个下拉框的Consumer未明确依赖itemProvider的变化,可能无法触发重新请求。
解决方案

1. 修复Provider配置

将ledgerItemProvider改为自动清理版本,避免内存泄漏:

final ledgerItemProvider = FutureProvider.family.autoDispose((ref, GetListModel model) => LedgerProvider().getLedgerItem(model));

2. 让GetListModel支持相等性判断

重写==和hashCode,确保Family Provider能正确识别参数变化:

class GetListModel {
  // 保留原有字段和toJson方法...

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is GetListModel &&
          runtimeType == other.runtimeType &&
          refName == other.refName &&
          isSingleList == other.isSingleList &&
          singleListNameStr == other.singleListNameStr &&
          listNameId == other.listNameId &&
          mainInfoModel == other.mainInfoModel &&
          conditionalValues == other.conditionalValues;

  @override
  int get hashCode =>
      refName.hashCode ^
      isSingleList.hashCode ^
      singleListNameStr.hashCode ^
      listNameId.hashCode ^
      mainInfoModel.hashCode ^
      conditionalValues.hashCode;
}

3. 关联第一个下拉框的选中值到API参数

在第二个下拉框的Consumer中,使用第一个下拉框的选中值动态生成API请求参数,替换硬编码的固定值:

// 第二个下拉框的Consumer builder内
final selectedGroup = ref.watch(itemProvider).test;

GetListModel ledgerGroupListModel = GetListModel();
ledgerGroupListModel.refName = 'AccountLedgerReport';
ledgerGroupListModel.isSingleList = 'true';
ledgerGroupListModel.singleListNameStr = 'account';
// 用选中的group值替换硬编码的35,根据后端API要求调整格式
ledgerGroupListModel.listNameId = "['mainLedger-${selectedGroup}']"; 
ledgerGroupListModel.mainInfoModel = mainInfo;
// 如果后端需要将选中分组作为条件参数,补充设置conditionalValues
ledgerGroupListModel.conditionalValues = selectedGroup; 

4. 完善API错误处理

修改LedgerProvider的getLedgerItem方法,请求失败时抛出错误,让Provider能进入Error状态排查问题:

Future<Map<dynamic, dynamic>> getLedgerItem(GetListModel getListModel) async {
  final dio = Dio();
  final jsonData = jsonEncode(getListModel.toJson());
  var ledger = {};
  try{
    final response = await dio.post(Api.getList, data: jsonData);
    if(response.statusCode == 200){
      final responseList = response.data as List<dynamic>;
      for(final e in responseList[0]){
        ledger[ListModel.fromJson(e).text!] = ListModel.fromJson(e).value!;
      }
      return ledger;
    }else{
      // 抛出错误,让Provider进入Error状态
      throw Exception('API请求失败,状态码: ${response.statusCode}');
    }
  }on DioError catch(err){
    throw DioException().getDioError(err);
  }
}

5. 确保依赖触发更新

第二个下拉框的Consumer已经嵌套在主Consumer中,且依赖itemProvider,当第一个下拉框选中值变化时,itemProvider通知更新,Consumer会重建并重新请求ledgerItemProvider,从而更新第二个下拉框数据。

验证要点
  • 检查第一个下拉框选中值是否正确传递到API参数中
  • 查看网络请求是否正常发送,后端是否返回正确数据
  • 若仍处于Loading状态,检查Error分支的输出,排查API请求问题

内容的提问来源于stack exchange,提问作者Bishal Rumba

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 17:18:22