Provider初始化时修改其他Provider报错,求该场景最佳实践
解决Provider初始化时修改其他Provider的错误及最佳实践
错误原因
你遇到的Providers are not allowed to modify other providers during their initialisation错误,是因为Riverpod禁止在Provider的初始化闭包里修改其他Provider的状态。初始化阶段是Provider创建自身的过程,此时修改外部状态会打破依赖关系的稳定性,引发不可预测的状态变化。
最佳实践方案
方案1:使用ref.listen监听状态变化
把对loadServicesProvider的状态监听和后续状态更新逻辑,从初始化闭包移到ref.listen中。listen会在Provider初始化完成后执行回调,此时修改其他Provider是安全的。
修改后的代码示例:
class CleansingServices extends StateNotifier<List<CleansingBaseModel>> { CleansingServices() : super([]); void setServices(List<CleansingBaseModel> data) { state = data; } } final cleansingServicesProvider = StateNotifierProvider<CleansingServices, List<CleansingBaseModel>>((ref) { final service = CleansingServices(); // 用listen监听loadServicesProvider的状态变化 ref.listen(loadServicesProvider, (previous, next) { final dataLoading = ref.read(cleansingLoadingStateProvider.notifier); next.when( data: (data) { service.setServices(data); dataLoading.setNotLoading(); }, error: (error, str) { dataLoading.setNotLoadingWithError(error); }, loading: () { dataLoading.setLoading(); }, ); }); return service; });
方案2:合并状态,使用AsyncValue管理加载状态
没必要单独维护一个cleansingLoadingStateProvider,可以直接让CleansingServices的状态是AsyncValue<List<CleansingBaseModel>>,这样加载、错误、数据状态都包含在同一个Provider里,组件可以直接通过when方法处理不同状态,避免跨Provider修改的问题。
重构后的代码示例:
class CleansingServices extends StateNotifier<AsyncValue<List<CleansingBaseModel>>> { CleansingServices(this.ref) : super(const AsyncLoading()) { _loadServices(); } final Ref ref; Future<void> _loadServices() async { try { final data = await ref.read(loadServicesProvider.future); state = AsyncData(data); } catch (e, stackTrace) { state = AsyncError(e, stackTrace); } } } final cleansingServicesProvider = StateNotifierProvider<CleansingServices, AsyncValue<List<CleansingBaseModel>>>((ref) { return CleansingServices(ref); });
在组件中使用时,直接通过when处理状态:
ref.watch(cleansingServicesProvider).when( loading: () => LoadingWidget(), error: (error, stack) => ErrorWidget(error), data: (services) => ServiceList(services: services), );
总结
- 避免在Provider初始化闭包中修改其他Provider的状态,改用
ref.listen处理跨Provider的状态更新 - 尽量将相关状态合并到同一个Provider中,使用
AsyncValue统一管理加载、错误、数据状态,简化逻辑
内容的提问来源于stack exchange,提问作者Naveed Ullah
相关产品推荐
相关产品推荐

