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

Flutter MobX如何修复Observer build方法未检测到可观察对象报错

Flutter MobX "No observables detected in the build method of Observer" 报错修复

报错根因

这个报错的核心触发逻辑是:Observer 的builder函数首次执行时,没有读取任何被@observable标记的响应式属性,MobX无法追踪到对应的响应式依赖,就会抛出该提示。
结合你贴的代码,问题集中在三点:

  1. Store类中的响应式属性没有正确添加@observable注解、修改状态的方法没有加@action注解,或是修改完Store代码后没有重新执行代码生成命令,导致MobX无法识别响应式属性
  2. 你在Observer外部通过Provider.of获取Store实例,部分用到响应式属性的逻辑(比如容器颜色判断、顶部文案判断)写在了Observer外部,既不会触发响应式更新,也可能导致Observer内部首次执行时无法正确读取到响应式属性
  3. 部分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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 21:24:29