Flutter Riverpod FutureProvider持续AsyncLoading,Dropdown联动API异常
问题描述
使用DropdownSearch组件实现三个下拉搜索框,初始通过单个API加载三个下拉框数据;需求是第一个下拉框选中项变更时,调用新API更新第二个下拉框数据,但实现后ledgerItemProvider始终处于AsyncLoading<Map<dynamic, dynamic>>状态,无法获取数据。
问题原因分析
- 参数硬编码未关联选中值:第二个下拉框的API请求参数(如
listNameId里的35)是固定值,没有使用第一个下拉框的选中项,导致请求的不是对应分组的数据,甚至可能因参数错误导致后端无响应。 - Family Provider参数相等性问题:
GetListModel未重写==和hashCode,Riverpod的Family Provider默认通过引用判断参数是否变化,每次重建都会生成新的GetListModel实例,可能导致不必要的重建或无法正确触发更新。 - Provider未配置自动清理:
ledgerItemProvider未使用.autoDispose,可能存在内存泄漏,且状态管理不够严谨。 - API错误处理不严谨:
LedgerProvider中请求失败时仅打印状态码,未抛出错误,导致Provider一直停留在Loading状态,无法进入Error状态暴露问题。 - 依赖未正确关联:第二个下拉框的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
相关产品推荐
相关产品推荐

