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
相关产品推荐
相关产品推荐

