常见问题 #
本文档收集了 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. 内存泄漏 #
问题:应用内存持续增长。
原因:没有清除 autorun、reaction、when。
解决方案:
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. 数组方法不生效 #
问题:数组方法如 find、filter 不触发更新。
原因:这些方法不会修改原数组,只是返回新数组。
解决方案:
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 错误、类型定义 |
| 调试问题 | 如何调试、如何查看状态 |
解决问题的关键:
- 使用 observer:确保组件能响应状态变化
- 正确使用 action:异步操作使用 runInAction 或 flow
- 合理拆分组件:减少不必要的更新
- 及时清理:清除不再需要的 reaction
- 类型明确:使用 TypeScript 时明确类型定义
恭喜你完成了 MobX 完全指南的学习!现在你已经掌握了 MobX 的核心概念和最佳实践,可以开始构建高效的状态管理应用了。
最后更新:2026-03-28