Flutter MobX如何修复Observer build方法未检测到可观察对象报错
Flutter MobX "No observables detected in the build method of Observer" 报错修复
报错根因
这个报错的核心触发逻辑是:Observer 的builder函数首次执行时,没有读取任何被@observable标记的响应式属性,MobX无法追踪到对应的响应式依赖,就会抛出该提示。
结合你贴的代码,问题集中在三点:
- Store类中的响应式属性没有正确添加
@observable注解、修改状态的方法没有加@action注解,或是修改完Store代码后没有重新执行代码生成命令,导致MobX无法识别响应式属性 - 你在
Observer外部通过Provider.of获取Store实例,部分用到响应式属性的逻辑(比如容器颜色判断、顶部文案判断)写在了Observer外部,既不会触发响应式更新,也可能导致Observer内部首次执行时无法正确读取到响应式属性 - 部分Observer的builder中存在条件判断逻辑,首次渲染时如果判断分支没有走到读取observable属性的路径,也会触发该报错。
修复步骤
第一步:校验Store类的注解配置,重新生成响应式代码
首先检查PomodoroStore的代码,确保所有需要触发UI更新的属性都加了@observable,所有修改响应式属性的方法都加了@action,正确的Store结构参考如下:
import 'package:mobx/mobx.dart'; // 必须引入build_runner生成的文件,不要遗漏 part 'pomodoro_store.g.dart'; class PomodoroStore = _PomodoroStore with _$PomodoroStore; abstract class _PomodoroStore with Store { // 需要响应式更新的属性必须加@observable注解 @observable int minutos = 25; @observable int segundos = 0; @observable bool start = false; @observable bool working = true; // 修改响应式状态的方法必须加@action注解 @action void startworking() { start = true; // 内置计时逻辑 } @action void stop() { start = false; } @action void restart() { // 内置重置逻辑 } bool isWorking() { return working; } }
修改完Store代码后,在项目根目录执行以下命令重新生成响应式代码:
flutter pub run build_runner build --delete-conflicting-outputs
超过60%的同类报错都是因为修改Store后没有重新执行代码生成,导致MobX的响应式代理没有更新。
第二步:调整Observer的包裹范围,保证依赖可被追踪
不要拆分零散的Observer导致部分builder首次执行读不到响应式属性,直接把所有用到Store响应式属性的UI逻辑统一包在一个Observer中,同时把Store实例的获取逻辑放到Observer的builder内部,修正后的Cronometro组件代码参考如下:
class Cronometro extends StatelessWidget { const Cronometro({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Observer( builder: (_) { // Store实例放在builder内部获取,保证所有响应式属性读取都能被MobX追踪 final store = Provider.of<PomodoroStore>(context); return Container( color: store.isWorking() ? Colors.redAccent : Colors.greenAccent, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( store.isWorking() ? "Time to work" : "Time to rest", style: TextStyle( fontSize: 40, color: Colors.white ), ), const SizedBox(height: 20), Text( '${store.minutos.toString().padLeft(2, '0')}:${store.segundos.toString().padLeft(2, '0')}', style: TextStyle( fontSize: 120, color: Colors.white ), ), const SizedBox(height: 20), SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ if(!store.start) Padding( padding: const EdgeInsets.only(right: 10), child: CronometroButton( text: 'Start', icon: Icons.play_arrow, click: store.startworking, ), ), if(store.start) Padding( padding: const EdgeInsets.only(right: 10), child: CronometroButton( text: 'Stop', icon: Icons.stop, click: store.stop, ), ), Padding( padding: const EdgeInsets.only(left: 10), child: CronometroButton( text: 'Restart', icon: Icons.refresh, click: store.restart, ), ), ], ), ), ], ), ); }, ); } }
额外排查点
如果完成以上两步后仍然报错,逐一排查以下问题:
- 不要在Observer的builder外部提前存储observable属性的值,所有响应式属性的读取必须放在builder函数内部,否则MobX无法追踪依赖变化
- 检查pubspec.yaml中的依赖版本,确保
mobx、flutter_mobx、build_runner、mobx_codegen四个包版本互相兼容,不要跨大版本混用 - 不要在Observer和Store获取逻辑之间插入其他拦截性组件嵌套,防止builder执行时拿不到正确的Store实例,导致无法读取observable属性
内容的提问来源于stack exchange,提问作者pomoworko.com
相关产品推荐
相关产品推荐

