MobX 深度解析
MobX 深度解析
一、核心概念
1. Observable(观察状态)
observable观察,可以使用observable包裹类来实现,创建响应式数据(类似Vue的reactive),
不过目前常用的方法是makeObservable和makeAutoObservable,会自动把当前class的自由对象为observable,get方法为computed,set方法为action 。
创建响应式数据的方法(类似 Vue 的 reactive):
// 方法一:使用 observable 包裹
import { observable } from 'mobx';
const user = observable({ name: 'John', age: 30 });
// 方法二:类中使用装饰器(常用)
import { makeObservable, observable, action, computed } from 'mobx';
class UserStore {
name = 'John';
age = 30;
constructor() {
makeObservable(this, {
name: observable,
age: observable,
// 其他配置...
});
}
}
// 方法三:自动观察(推荐)
import { makeAutoObservable } from 'mobx';
class UserStore {
name = 'John';
age = 30;
constructor() {
makeAutoObservable(this);
// 自动将:
// - 属性标记为 observable
// - getter 标记为 computed
// - 方法标记为 action
}
get isAdult() {
return this.age >= 18; // 自动成为 computed
}
setName(name) {
this.name = name; // 自动成为 action
}
}
2. Action(状态变更)
action的用法,只有是类的字段的函数方法会被makeAutoObservable自动包装为action,
如果是在异步回调如promise中要显式的action包装,使用action或 runInAction方法,或者使用flow (generator),即*标注为生成器函数,用yield替代await。
核心原则:所有状态变更都应该在 action 中执行。
import { action, runInAction, flow } from 'mobx';
class UserStore {
// 同步 action(自动标记)
updateName(name) {
this.name = name;
}
// 异步 action 方案一:runInAction
async fetchUser() {
const response = await fetch('/api/user');
runInAction(() => {
this.user = response.data;
});
}
// 异步 action 方案二:flow(生成器函数)
*fetchUserFlow() {
const response = yield fetch('/api/user');
this.user = response.data; // 自动在 action 中
}
}
// 强制使用 action 修改状态(推荐)
import { configure } from 'mobx';
configure({ enforceActions: 'always' });
3. Reactions(反应)
reactions,可以看作是useeffect副作用的概念,更像是vue中的watch,computed也类似vue的computed。
autorun可以自动追踪依赖变化,类似vue的WatchEffect;也可以使用reaction或者when方法,类似vue的watch,需要显式的声明监听依赖对象。
When方法的特点是,满足特定条件时执行一次,执行后自动清理,后续不会再触发。
类似于 Vue 的 watch 和 computed:
import { autorun, reaction, when, computed } from 'mobx';
// 1. autorun:自动追踪依赖(类似 Vue 的 watchEffect)
const disposer = autorun(() => {
console.log(`User: ${user.name}, Age: ${user.age}`);
});
// 2. reaction:显式声明依赖(类似 Vue 的 watch)
reaction(
() => user.age, // 跟踪的表达式
(age, previousAge) => {
console.log(`Age changed from ${previousAge} to ${age}`);
}
);
// 3. when:条件执行一次
when(
() => user.age >= 18, // 条件
() => {
console.log('User is now an adult');
} // 执行后自动清理
);
// 4. computed:计算属性
class UserStore {
get displayName() {
return `${this.name} (${this.age})`;
}
}
4. 在 React 中集成 MobX
在react中集成mobx,一般会选择observer观察某个需要响应式更新的组件,以此实现类似于vue中默认的响应式组件。
需要注意的是,observer包裹的组件,其中的观察对象或者说属性,需要是一个observable,所以经常会使用useLocalObservable来创建一个局部的响应式对象。
要把一个observable赋值给react组件时,必须将其转换回js对象,一般使用toJS方法。
在useEffect 中,组件销毁时记得清理autorun/reaction,使用disposer(),when执行后会自动清理,但如果未执行也应清理,使用whenDisposer。
import { observer, useLocalObservable } from 'mobx-react-lite';
import { toJS } from 'mobx';
import { useEffect } from 'react';
// 1. 使用 observer 包装组件
const UserComponent = observer(({ userStore }) => {
// 2. 创建局部响应式对象
const localState = useLocalObservable(() => ({
count: 0,
increment() {
this.count++;
}
}));
// 3. 转换 observable 为普通 JS 对象
const userData = toJS(userStore.user);
// 4. 在 useEffect 中处理 reactions
useEffect(() => {
const disposer = autorun(() => {
console.log('User changed:', userStore.name);
});
// 清理函数
return () => disposer();
}, [userStore]);
// 5. when 的清理
useEffect(() => {
const whenDisposer = when(
() => userStore.age >= 18,
() => console.log('Became adult')
);
return () => whenDisposer(); // 如果 when 未执行,需要手动清理
}, [userStore]);
return <div>{userStore.name}</div>;
});
二、最佳实践
1. 状态管理模式
// Store 模式
class RootStore {
constructor() {
this.userStore = new UserStore(this);
this.uiStore = new UIStore(this);
}
}
// 使用 Context 提供 Store
const StoreContext = React.createContext();
const useStore = () => useContext(StoreContext);
2. 性能优化
// 1. 使用 observer 精细控制
const UserList = observer(({ users }) => (
<div>
{users.map(user => (
<UserItem key={user.id} user={user} />
))}
</div>
));
// 2. 避免不必要的重新渲染
const UserItem = observer(({ user }) => (
<div>{user.name}</div>
));
// 3. 批量更新
import { runInAction } from 'mobx';
const updateMultiple = () => {
runInAction(() => {
store.user.name = 'New Name';
store.user.age = 31;
});
};
3. 调试技巧
import { trace } from 'mobx';
// 跟踪 computed/action 的执行
class UserStore {
get displayName() {
trace(); // 在控制台显示依赖追踪
return `${this.name} (${this.age})`;
}
}
// 配置开发工具
import { configure } from 'mobx';
configure({
enforceActions: 'always',
computedRequiresReaction: true,
reactionRequiresObservable: true,
observableRequiresReaction: false,
disableErrorBoundaries: false
});
三、与 Vue 的对比
| 特性 | MobX + React | Vue |
|---|---|---|
| 响应式基础 | 显式使用 observable |
默认响应式 |
| 状态变更 | 需要 action 包装 |
直接赋值 |
| 计算属性 | computed getter |
computed 函数 |
| 副作用 | autorun/reaction/when |
watch/watchEffect |
| 组件更新 | 需要 observer 包装 |
默认自动更新 |
| 异步处理 | runInAction/flow |
直接赋值,自动追踪 |
四、总结
MobX + React ≈ Vue 的自动响应式能力
MobX 为 React 提供了类似 Vue 的自动响应式系统:
- 声明式状态:使用
observable声明响应式数据 - 自动追踪:依赖自动收集,变更自动触发更新
- 细粒度更新:只有真正变化的组件重新渲染
- 简单直观:相比 Redux 减少了模板代码
适用场景:
- 需要快速开发的中大型应用
- 团队熟悉面向对象编程
- 希望获得 Vue 式开发体验的 React 项目
注意事项:
- 始终在
action中修改状态 - 使用
observer包装需要响应式更新的组件 - 及时清理
reactions避免内存泄漏 - 考虑使用
makeAutoObservable简化代码

浙公网安备 33010602011771号