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

Riverpod触发重建后读取未初始化Provider状态报错的解决方法

Riverpod Notifier重建时保留选中状态的报错解决

问题背景

我用Riverpod实现了一个Notifier,期望数据更新后触发重建,同时不丢失之前选中对象的引用。代码如下:

@Riverpod(keepAlive:true)
Future<List<MyModel>> modelList (ModelListRef ref) {
    return ref.watch(modelRepositoryProvider).getModels();
}

@Riverpod(keepAlive:true)
class MyController extends _$MyController {
  
  @override
  MyModel? build() {
    return ref.watch(modelListProvider).maybeWhen(
      // 此处访问state会触发错误 ↓
      data: (models) => models.singleWhereOrNull((model) => model.id == state?.id),
      orElse: () => null,
    );
  }
  
  @override 
  set state (MyModel value){
    state = value;
   }
}

修改数据后调用ref.invalidate(modelListProvider)触发重建,读取Notifier状态时抛出错误:

StateError (Bad state: Tried to read the state of an uninitialized provider)

堆栈信息指向Notifier的state属性。

问题根源

  1. 初始化阶段访问未就绪的state:build方法是用来初始化Notifier状态的,此时Notifier还未完成初始化,直接访问state会触发未初始化错误。
  2. 无限递归的setter:自定义的set state方法中直接赋值state = value,会无限递归调用自身,导致状态无法正确更新。

解决方案

通过单独存储选中对象的ID,避免在build阶段依赖未初始化的state,同时修复setter的递归问题:

@Riverpod(keepAlive:true)
Future<List<MyModel>> modelList (ModelListRef ref) {
    return ref.watch(modelRepositoryProvider).getModels();
}

@Riverpod(keepAlive:true)
class MyController extends _$MyController {
  // 单独存储选中模型的ID,脱离对state的依赖
  String? _selectedModelId;

  @override
  MyModel? build() {
    return ref.watch(modelListProvider).maybeWhen(
      data: (models) {
        // 用存储的ID匹配新列表中的模型
        if (_selectedModelId == null) return null;
        return models.singleWhereOrNull((model) => model.id == _selectedModelId);
      },
      orElse: () => null,
    );
  }

  // 修复setter的递归问题,调用父类的state setter
  @override 
  set state (MyModel? value){
    _selectedModelId = value?.id;
    super.state = value;
  }
}

说明

  • 新增_selectedModelId变量存储选中对象的ID,build方法通过这个ID从更新后的模型列表中匹配对应对象,既实现了状态同步,又避免了初始化阶段访问state的问题。
  • 自定义state setter时,先更新_selectedModelId,再调用super.state = value,既保留了选中状态,又解决了无限递归的问题。
  • 当调用ref.invalidate(modelListProvider)后,modelListProvider重新获取数据,MyController会自动用存储的ID匹配新模型,完成状态更新,同时保留选中对象的关联。

内容的提问来源于stack exchange,提问作者Christian

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 02:25:27