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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 01:05:22