Riverpod StateNotifier报错时展示SnackBar并保留历史加载列表
问题核心原因
你当前的状态设计将SalesOrderListSuccess和SalesOrderListError作为完全独立的平级状态,当请求失败触发状态切换为SalesOrderListError时,状态内不再持有之前加载成功的列表数据,同时你在组件内强制将状态转换为SalesOrderListSuccess类型会触发类型转换异常,自然无法保留原有UI。
解决方案
推荐优先调整状态类结构,让错误状态可以携带最后一次成功的列表数据,无需大幅修改原有逻辑:
步骤1:修改状态类定义
给错误状态新增字段存储最后一次加载成功的列表:
class SalesOrderListError extends SalesOrderListState { final dynamic error; // 新增字段存储最后一次成功获取的列表 final List<SalesOrderListItem> lastSuccessItems; const SalesOrderListError({ required this.error, required this.lastSuccessItems, }); @override List<Object?> get props => [error, lastSuccessItems]; }
步骤2:调整StateNotifier的错误状态赋值逻辑
触发请求失败时,将已缓存的列表数据传入错误状态:
// 原有请求失败逻辑 // state = SalesOrderListError(error: response.data); // 修改为 state = SalesOrderListError( error: response.data, // _items是你之前存储加载成功列表的变量 lastSuccessItems: _items, );
步骤3:修改Widget代码,兼容多状态渲染
@override Widget build(BuildContext context, WidgetRef ref) { final todos = ref.watch(todoListProvider); final selectedtrack = ref.read(selectedProductIdProvider2.notifier); // 提取要展示的列表,兼容两种状态 List<SalesOrderListItem> showItems = []; if (todos is SalesOrderListSuccess) { showItems = todos.salesOrderListItems; } else if (todos is SalesOrderListError) { showItems = todos.lastSuccessItems; } ref.listen(todoListProvider, (previous, current) { if (current is SalesOrderListError) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('请求出错,请稍后重试')), ); } }); // 仅从未加载到成功数据时才展示空页,已有数据时直接渲染列表 if (showItems.isEmpty) { return const Center(child: Text('暂无销售订单数据')); } return ListView.builder( shrinkWrap: true, physics: const ClampingScrollPhysics(), itemCount: showItems.length, itemBuilder: (context, index) { final current = showItems[index]; return ListTile( title: Text('${current.title}'), onTap: () { selectedtrack.state = index; Navigator.push( context, MaterialPageRoute( builder: (context) => const DetailScreen(), ), ); } ); }, ); }
可选优化方案
如果不想拆分多状态类,也可以直接将状态类改为统一结构,始终持有列表、错误、加载状态三个属性,更新时仅修改对应属性即可,状态切换时不会丢失已加载的列表数据:
class SalesOrderListState extends Equatable { final List<SalesOrderListItem> items; final dynamic error; final bool isLoading; const SalesOrderListState({ this.items = const [], this.error, this.isLoading = false, }); SalesOrderListState copyWith({ List<SalesOrderListItem>? items, dynamic? error, bool? isLoading, }) => SalesOrderListState( items: items ?? this.items, // 错误字段主动清空,避免上次错误重复提示 error: error, isLoading: isLoading ?? this.isLoading, ); @override List<Object?> get props => [items, error, isLoading]; }
内容的提问来源于stack exchange,提问作者Lundin
相关产品推荐
相关产品推荐

