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

Flutter Riverpod:如何避免ChangeNotifier构造用ref.watch触发实例重建

问题根因

你在ChangeNotifier构造函数中使用ref.watch的写法,会给当前的ChangeNotifierProvider注册对otherProvider的依赖,只要otherProvider的监听值发生变化,就会触发整个ChangeNotifierProvider的重建逻辑,直接生成新的CategoryViewState实例,旧实例的所有状态自然会丢失。

修复方案

方案1:用ref.listen替代ref.watch(最推荐)

ref.listen只会监听依赖的变化,不会触发当前Provider的重建,你可以手动处理变化后的赋值逻辑,不会影响实例本身的其他状态:

CategoryViewState(ProviderRefBase ref, int listId) {
    // 先读取初始值赋值
    subjects = ref.read(otherProvider.select((value) => value.getSubjects()));
    // 监听后续值变化,手动更新字段并通知刷新
    ref.listen(
      otherProvider.select((value) => value.getSubjects()),
      (previous, next) {
        subjects = next;
        notifyListeners();
      },
    );
}

方案2:将监听逻辑移到组件层

如果不想在ChangeNotifier内部处理依赖监听,也可以在使用subjects的组件层直接监听otherProvider的变化,拿到新值后调用CategoryViewState的公开方法更新字段:

// 组件层的build方法中
final subjects = ref.watch(otherProvider.select((value) => value.getSubjects()));
ref.read(categoryViewStateProvider.notifier).updateSubjects(subjects);

// CategoryViewState中新增更新方法
void updateSubjects(List<Subject> newSubjects) {
  subjects = newSubjects;
  notifyListeners();
}

方案3:拆分状态Provider

如果subjects本身和CategoryViewState的其他业务状态耦合度很低,可以直接把subjects独立成单独的Provider,不需要放到CategoryViewState里管理,自然也不会触发状态丢失的问题。

注意事项

  • 不要在ChangeNotifier/StateNotifier等持久化状态类的构造函数、成员初始化逻辑中使用ref.watch,该API仅适用于需要随依赖变化重新执行的上下文(比如Provider创建回调、组件build方法)
  • 状态类内部如果需要响应其他Provider的变化,统一用ref.listen做事件监听,手动处理状态更新

内容的提问来源于stack exchange,提问作者mosh.jinton

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 05:54:04