Flutter-Riverpod Future Provider:报错时如何保留旧数据?
Riverpod刷新出错时保留现有数据的解决方案
默认FutureProvider在刷新数据失败时,会将状态切换为error,覆盖之前的data,导致现有数据丢失、UI直接切换到错误组件。要实现刷新失败保留旧数据的需求,最优雅的方式是用StateNotifierProvider手动管控状态逻辑,具体实现如下:
1. 定义状态类
创建一个包含数据、加载状态、错误信息的状态模型,方便精细化更新:
class DataState<T> { final T? data; final bool isLoading; final Object? error; DataState({ this.data, this.isLoading = false, this.error, }); // 拷贝方法,仅更新指定字段,保留其他原有状态 DataState<T> copyWith({ T? data, bool? isLoading, Object? error, }) { return DataState<T>( data: data ?? this.data, isLoading: isLoading ?? this.isLoading, error: error ?? this.error, ); } }
2. 实现StateNotifier
编写状态控制器,在刷新失败时仅更新错误和加载状态,不清除现有数据:
class DataNotifier<T> extends StateNotifier<DataState<T>> { final Future<T> Function() fetchData; DataNotifier(this.fetchData) : super(DataState<T>()) { // 初始化时自动加载数据 _loadInitialData(); } Future<void> _loadInitialData() async { state = state.copyWith(isLoading: true); try { final newData = await fetchData(); state = state.copyWith( data: newData, isLoading: false, error: null, ); } catch (e) { state = state.copyWith( isLoading: false, error: e, ); } } // 手动刷新方法,失败保留旧数据 Future<void> refresh() async { state = state.copyWith(isLoading: true); try { final newData = await fetchData(); state = state.copyWith( data: newData, isLoading: false, error: null, ); } catch (e) { // 仅更新错误和加载状态,data字段沿用旧值 state = state.copyWith( isLoading: false, error: e, ); } } }
3. 创建Provider
注册对应的StateNotifierProvider:
final dataProvider = StateNotifierProvider<DataNotifier<MyModel>, DataState<MyModel>>((ref) { return DataNotifier(() => fetchData()); // 传入你的数据获取方法 });
4. UI层使用
在组件中监听状态,即使刷新出错,现有数据依然保留,错误提示可叠加显示而非替换数据组件:
final dataState = ref.watch(dataProvider); return Stack( children: [ // 始终显示现有数据(如果存在) if (dataState.data != null) DataWidget(dataState.data!), // 加载状态覆盖显示 if (dataState.isLoading) LoadingWidget(), // 错误状态可放在角落或顶部,不替换数据 if (dataState.error != null && !dataState.isLoading) Positioned( top: 16, left: 0, right: 0, child: ErrorWidget(dataState.error!), ), ], );
5. 触发刷新
用户触发刷新时调用控制器的refresh方法即可:
ref.read(dataProvider.notifier).refresh();
这种方案的核心是通过StateNotifier完全掌控状态更新逻辑,避免了默认FutureProvider状态切换时丢失旧数据的问题,同时能灵活控制加载、错误、数据的显示逻辑。
内容的提问来源于stack exchange,提问作者Palejandro
相关产品推荐
相关产品推荐

