常见问题 #

本文档收集了 MobX 开发中常见的问题和解决方案,帮助你快速定位和解决问题。

基础问题 #

1. 组件不更新 #

问题:修改了状态,但组件没有重新渲染。

原因

  • 没有使用 observer 包装组件
  • observer 外访问状态
  • 解构了可观察对象

解决方案

javascript
import { observer } from 'mobx-react-lite';

// 错误:没有 observer
const Counter = () => {
  return <div>{store.count}</div>;
};

// 正确:使用 observer
const Counter = observer(() => {
  return <div>{store.count}</div>;
});

// 错误:在 observer 外访问
const count = store.count;
const Counter = observer(() => {
  return <div>{count}</div>;
});

// 正确:在 observer 内访问
const Counter = observer(() => {
  return <div>{store.count}</div>;
});

// 错误:解构失去响应性
const Counter = observer(() => {
  const { count } = store;
  return <div>{count}</div>;
});

// 正确:直接访问
const Counter = observer(() => {
  return <div>{store.count}</div>;
});

2. 状态修改不生效 #

问题:修改状态后没有触发更新。

原因

  • 修改了不可观察的属性
  • 直接修改了嵌套对象(浅层观察)

解决方案

javascript
import { makeAutoObservable, makeObservable, observable } from 'mobx';

// 错误:属性没有被观察
class Store {
  count = 0;
}
const store = new Store();
store.count++;  // 不会触发更新

// 正确:使用 makeAutoObservable
class Store {
  count = 0;
  constructor() {
    makeAutoObservable(this);
  }
}

// 错误:浅层观察
class Store {
  constructor() {
    makeAutoObservable(this);
  }
  user = { name: 'John' };  // 嵌套对象默认是深度观察的
}

// 如果使用 shallow
const store = observable.shallow({
  user: { name: 'John' }
});
store.user.name = 'Jane';  // 不会触发更新

// 正确:使用深度观察
const store = observable({
  user: { name: 'John' }
});
store.user.name = 'Jane';  // 会触发更新

3. 异步操作报错 #

问题:在异步操作中修改状态报错。

原因:配置了 enforceActions: 'always',异步代码不在 action 中。

解决方案

javascript
import { runInAction, flow, makeAutoObservable } from 'mobx';

class Store {
  data = null;

  constructor() {
    makeAutoObservable(this);
  }

  // 方案1:使用 runInAction
  async fetchData1() {
    const response = await fetch('/api/data');
    const data = await response.json();

    runInAction(() => {
      this.data = data;
    });
  }

  // 方案2:使用 flow(推荐)
  fetchData2 = flow(function* () {
    const response = yield fetch('/api/data');
    const data = yield response.json();
    this.data = data;
  });
}

性能问题 #

4. 组件频繁更新 #

问题:组件更新太频繁,影响性能。

原因

  • 组件追踪了太多状态
  • 没有合理拆分组件

解决方案

javascript
import { observer } from 'mobx-react-lite';

// 错误:一个大组件追踪所有状态
const App = observer(() => (
  <div>
    <Header user={userStore.user} />
    <Content items={itemStore.items} />
    <Footer count={counterStore.count} />
  </div>
));

// 正确:拆分组件,各自追踪需要的状态
const Header = observer(() => (
  <header>{userStore.user.name}</header>
));

const Content = observer(() => (
  <main>{itemStore.items.map(...)}</main>
));

const Footer = observer(() => (
  <footer>{counterStore.count}</footer>
));

const App = () => (
  <div>
    <Header />
    <Content />
    <Footer />
  </div>
));

5. 计算值重复计算 #

问题:计算值每次访问都重新计算。

原因

  • 计算值依赖不稳定(每次返回新对象)
  • 在计算值中使用了随机数或时间

解决方案

javascript
import { computed, makeAutoObservable } from 'mobx';

class Store {
  items = [];

  constructor() {
    makeAutoObservable(this);
  }

  // 错误:每次返回新对象
  get badComputed() {
    return { count: this.items.length };  // 每次都是新对象
  }

  // 正确:使用 computed.struct
  get goodComputed() {
    return { count: this.items.length };
  }
  // 配置
  // makeAutoObservable(this, { goodComputed: computed.struct })
}

6. 内存泄漏 #

问题:应用内存持续增长。

原因:没有清除 autorunreactionwhen

解决方案

javascript
import { autorun, reaction, when } from 'mobx';

// 组件中
useEffect(() => {
  const dispose = autorun(() => {
    console.log(store.count);
  });

  return () => dispose();
}, []);

// 类中
class Store {
  disposers = [];

  constructor() {
    this.disposers.push(
      autorun(() => { })
    );
    this.disposers.push(
      reaction(() => this.count, () => { })
    );
  }

  destroy() {
    this.disposers.forEach(d => d());
  }
}

类型问题 #

7. TypeScript类型错误 #

问题:TypeScript 报类型错误。

解决方案

typescript
import { makeAutoObservable, observable } from 'mobx';

// 明确类型
class Store {
  count: number = 0;
  name: string = '';
  items: Item[] = [];

  constructor() {
    makeAutoObservable(this);
  }
}

// 使用接口
interface User {
  id: number;
  name: string;
}

class UserStore {
  users: User[] = [];

  constructor() {
    makeAutoObservable(this);
  }
}

// 泛型 Store
class AsyncStore<T> {
  data: T | null = null;
  loading: boolean = false;

  constructor() {
    makeAutoObservable(this);
  }
}

8. observable.box类型 #

问题observable.box 的类型问题。

解决方案

typescript
import { observable, IObservableValue } from 'mobx';

// 明确类型
const count = observable.box<number>(0);
const name = observable.box<string>('');

// 使用类型
const countValue: number = count.get();
count.set(1);

// IObservableValue 类型
const observableNumber: IObservableValue<number> = observable.box(0);

调试问题 #

9. 如何调试MobX #

解决方案

javascript
import { spy, trace, whyRun } from 'mobx';

// 全局监听
spy((event) => {
  console.log('MobX Event:', event);
});

// 追踪特定计算
class Store {
  constructor() {
    makeAutoObservable(this);
  }

  get computed() {
    // 追踪这个计算
    trace();
    return this.count * 2;
  }
}

// 查看为什么运行
whyRun();

10. 如何查看状态变化 #

解决方案

javascript
import { autorun, toJS } from 'mobx';

// 监听状态变化
autorun(() => {
  console.log('State:', toJS(store));
});

// 使用 spy
spy((event) => {
  if (event.type === 'action') {
    console.log(`Action: ${event.name}`);
    console.log('Arguments:', event.arguments);
  }
});

// 使用 reaction
reaction(
  () => toJS(store),
  (state) => {
    console.log('State changed:', state);
  }
);

其他问题 #

11. 数组方法不生效 #

问题:数组方法如 findfilter 不触发更新。

原因:这些方法不会修改原数组,只是返回新数组。

解决方案

javascript
class Store {
  items = [];

  constructor() {
    makeAutoObservable(this);
  }

  // 错误:filter 不会修改原数组
  removeInactive() {
    this.items.filter(item => item.active);  // 不生效
  }

  // 正确:重新赋值
  removeInactive() {
    this.items = this.items.filter(item => item.active);
  }

  // 或者使用 splice
  removeItem(index) {
    this.items.splice(index, 1);
  }
}

12. Map/Set问题 #

问题:Map/Set 操作不触发更新。

解决方案

javascript
import { observable, makeAutoObservable } from 'mobx';

// 使用 MobX 的 observable Map/Set
class Store {
  userMap = observable.map();
  tags = observable.set();

  constructor() {
    makeAutoObservable(this);
  }

  // 正确使用
  addUser(id, user) {
    this.userMap.set(id, user);
  }

  addTag(tag) {
    this.tags.add(tag);
  }
}

13. 继承问题 #

问题:继承 Store 时出现问题。

解决方案

javascript
import { makeObservable, observable } from 'mobx';

// 使用 makeObservable 而不是 makeAutoObservable
class BaseStore {
  loading = false;

  constructor() {
    makeObservable(this, {
      loading: observable
    });
  }
}

class UserStore extends BaseStore {
  users = [];

  constructor() {
    super();
    makeObservable(this, {
      users: observable
    });
  }
}

总结 #

常见问题分类:

类别 常见问题
基础问题 组件不更新、状态修改不生效、异步操作报错
性能问题 频繁更新、重复计算、内存泄漏
类型问题 TypeScript 错误、类型定义
调试问题 如何调试、如何查看状态

解决问题的关键:

  1. 使用 observer:确保组件能响应状态变化
  2. 正确使用 action:异步操作使用 runInAction 或 flow
  3. 合理拆分组件:减少不必要的更新
  4. 及时清理:清除不再需要的 reaction
  5. 类型明确:使用 TypeScript 时明确类型定义

恭喜你完成了 MobX 完全指南的学习!现在你已经掌握了 MobX 的核心概念和最佳实践,可以开始构建高效的状态管理应用了。

最后更新:2026-03-28