MobX核心概念 #
MobX 的核心概念可以概括为三个部分:State(状态)、Actions(动作) 和 Derivations(派生)。理解这三个概念是掌握 MobX 的关键。
核心概念概览 #
text
┌─────────────────────────────────────────────────────────────┐
│ MobX 架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────────┐ │
│ │ Actions │ ──────► │ State │ │
│ │ 动作 │ │ 状态 │ │
│ └─────────┘ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Derivations │ │
│ │ 派生 │ │
│ └────────┬────────┘ │
│ │ │
│ ┌──────────────┼──────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Computed │ │ Reactions│ │ UI │ │
│ │ 计算值 │ │ 反应 │ │ 界面 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
一、State(状态) #
State 是应用的数据源,是驱动应用运行的核心。在 MobX 中,状态是可观察的(Observable)。
定义状态 #
javascript
import { makeAutoObservable, observable } from 'mobx';
// 方式一:使用 makeAutoObservable(推荐)
class TodoStore {
todos = [];
filter = 'all';
constructor() {
makeAutoObservable(this);
}
}
// 方式二:使用 observable 函数
const state = observable({
count: 0,
name: 'MobX'
});
// 方式三:使用装饰器(需要配置)
class Store {
@observable count = 0;
@observable name = 'MobX';
}
状态的特点 #
- 可观察性:状态变化会被自动追踪
- 响应式:状态变化会触发相关更新
- 可变性:可以直接修改状态
javascript
const store = new TodoStore();
// 直接修改状态
store.todos.push({ id: 1, title: 'Learn MobX' });
store.filter = 'completed';
可观察的数据类型 #
MobX 可以让以下数据类型变为可观察:
javascript
import { makeAutoObservable } from 'mobx';
class Store {
// 基本类型
string = 'hello';
number = 42;
boolean = true;
// 对象
object = { name: 'MobX', version: 6 };
// 数组
array = [1, 2, 3];
// Map 和 Set
map = new Map();
set = new Set();
constructor() {
makeAutoObservable(this);
}
}
二、Actions(动作) #
Actions 是修改状态的唯一途径。使用 Action 可以让状态变化变得可追踪、可调试。
定义动作 #
javascript
import { makeAutoObservable, action } from 'mobx';
class CounterStore {
count = 0;
constructor() {
makeAutoObservable(this);
}
// 方式一:方法自动成为 action
increment() {
this.count++;
}
decrement() {
this.count--;
}
// 方式二:使用 action 包装
reset = action(() => {
this.count = 0;
});
}
动作的特点 #
- 批量更新:多个状态修改只触发一次更新
- 事务性:状态修改是原子操作
- 可追踪:便于调试和日志记录
javascript
class TodoStore {
todos = [];
constructor() {
makeAutoObservable(this);
}
// 批量修改,只触发一次更新
addTodo(title) {
this.todos.push({
id: Date.now(),
title,
completed: false
});
}
// 复杂操作
toggleTodo(id) {
const todo = this.todos.find(t => t.id === id);
if (todo) {
todo.completed = !todo.completed;
}
}
}
action.bound #
使用 action.bound 自动绑定 this:
javascript
class Store {
count = 0;
constructor() {
makeAutoObservable(this);
}
// 自动绑定 this
increment = action(() => {
this.count++;
});
// 或者使用 makeAutoObservable 的 autoBind 选项
// makeAutoObservable(this, {}, { autoBind: true });
}
const store = new Store();
const { increment } = store;
increment(); // this 正确绑定
异步动作 #
处理异步操作时,推荐使用 runInAction:
javascript
import { makeAutoObservable, runInAction } from 'mobx';
class UserStore {
users = [];
loading = false;
constructor() {
makeAutoObservable(this);
}
async fetchUsers() {
this.loading = true;
try {
const response = await fetch('/api/users');
const users = await response.json();
// 在 action 中修改状态
runInAction(() => {
this.users = users;
this.loading = false;
});
} catch (error) {
runInAction(() => {
this.loading = false;
});
}
}
}
三、Derivations(派生) #
Derivations 是从状态派生出来的值或副作用。MobX 会自动追踪派生对状态的依赖,并在状态变化时自动更新。
Computed Values(计算值) #
计算值是从状态派生出来的值,具有缓存特性:
javascript
import { makeAutoObservable, computed } from 'mobx';
class TodoStore {
todos = [];
filter = 'all';
constructor() {
makeAutoObservable(this);
}
// 计算值 - 自动缓存
get filteredTodos() {
switch (this.filter) {
case 'completed':
return this.todos.filter(t => t.completed);
case 'active':
return this.todos.filter(t => !t.completed);
default:
return this.todos;
}
}
// 另一个计算值
get completedCount() {
return this.todos.filter(t => t.completed).length;
}
get totalCount() {
return this.todos.length;
}
}
计算值的特点 #
- 自动缓存:只有依赖变化时才重新计算
- 惰性求值:只有被访问时才计算
- 响应式:依赖变化时自动更新
javascript
const store = new TodoStore();
// 第一次访问,计算并缓存
console.log(store.filteredTodos);
// 再次访问,直接返回缓存值
console.log(store.filteredTodos);
// 修改状态,缓存失效
store.filter = 'completed';
// 重新计算
console.log(store.filteredTodos);
Reactions(反应) #
Reactions 是状态变化时自动执行的副作用:
autorun #
javascript
import { autorun } from 'mobx';
const store = new TodoStore();
// 自动运行,状态变化时重新执行
const dispose = autorun(() => {
console.log(`Total: ${store.todos.length}`);
console.log(`Completed: ${store.completedCount}`);
});
// 清除
dispose();
reaction #
javascript
import { reaction } from 'mobx';
// 精确追踪特定状态
const dispose = reaction(
// 追踪函数 - 返回要追踪的值
() => store.todos.length,
// 副作用函数 - 值变化时执行
(length, previousLength) => {
console.log(`Todos changed from ${previousLength} to ${length}`);
}
);
when #
javascript
import { when } from 'mobx';
// 条件满足时执行一次
when(
() => store.todos.length > 10,
() => {
console.log('Todos exceeded 10!');
}
);
完整示例 #
下面是一个完整的 Todo 应用示例:
javascript
import { makeAutoObservable, computed, autorun } from 'mobx';
import { observer } from 'mobx-react-lite';
// Store
class TodoStore {
todos = [];
filter = 'all';
constructor() {
makeAutoObservable(this);
}
// Actions
addTodo(title) {
this.todos.push({
id: Date.now(),
title,
completed: false
});
}
toggleTodo(id) {
const todo = this.todos.find(t => t.id === id);
if (todo) {
todo.completed = !todo.completed;
}
}
setFilter(filter) {
this.filter = filter;
}
// Computed
get filteredTodos() {
switch (this.filter) {
case 'completed':
return this.todos.filter(t => t.completed);
case 'active':
return this.todos.filter(t => !t.completed);
default:
return this.todos;
}
}
get completedCount() {
return this.todos.filter(t => t.completed).length;
}
get activeCount() {
return this.todos.length - this.completedCount;
}
}
// 创建实例
const todoStore = new TodoStore();
// Reaction - 自动保存到 localStorage
autorun(() => {
localStorage.setItem('todos', JSON.stringify(todoStore.todos));
});
// React 组件
const TodoApp = observer(() => (
<div>
<h1>Todos ({todoStore.activeCount} remaining)</h1>
<ul>
{todoStore.filteredTodos.map(todo => (
<li
key={todo.id}
onClick={() => todoStore.toggleTodo(todo.id)}
style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
>
{todo.title}
</li>
))}
</ul>
<button onClick={() => todoStore.setFilter('all')}>All</button>
<button onClick={() => todoStore.setFilter('active')}>Active</button>
<button onClick={() => todoStore.setFilter('completed')}>Completed</button>
</div>
));
核心原则 #
MobX 遵循以下核心原则:
1. 单一数据源 #
javascript
// 推荐:单一 Store
const store = new AppStore();
// 或按功能拆分
const userStore = new UserStore();
const todoStore = new TodoStore();
2. 状态只读,通过 Action 修改 #
javascript
// 错误:直接修改(虽然可以工作)
store.count++;
// 正确:通过 Action 修改
store.increment();
3. 派生数据使用 Computed #
javascript
// 错误:存储派生值
class Store {
todos = [];
completedCount = 0; // 不应该存储
updateCompletedCount() {
this.completedCount = this.todos.filter(t => t.completed).length;
}
}
// 正确:使用计算值
class Store {
todos = [];
get completedCount() {
return this.todos.filter(t => t.completed).length;
}
}
总结 #
MobX 的三大核心概念:
| 概念 | 说明 | 特点 |
|---|---|---|
| State | 应用状态 | 可观察、可变 |
| Actions | 修改状态 | 批量更新、可追踪 |
| Derivations | 派生数据 | 自动更新、缓存 |
理解这三个概念是掌握 MobX 的基础。继续学习 Observable状态,深入了解如何创建可观察状态。
最后更新:2026-03-28