Observable状态 #
Observable(可观察)是 MobX 响应式系统的基础。通过将状态变为可观察,MobX 可以自动追踪状态的读取和修改,从而实现响应式更新。
什么是Observable? #
Observable 是一种特殊的数据结构,它允许 MobX 追踪:
- 读取操作:谁在读取这个值
- 修改操作:这个值何时被修改
text
普通对象 Observable对象
┌─────────────┐ ┌─────────────────────┐
│ { │ │ { │
│ a: 1 │ │ a: 1 ← 追踪读取 │
│ b: 2 │ ───► │ b: 2 ← 追踪写入 │
│ } │ │ } │
└─────────────┘ └─────────────────────┘
创建Observable #
observable函数 #
observable 函数可以将对象、数组、Map、Set 等变为可观察:
javascript
import { observable } from 'mobx';
// 对象
const person = observable({
name: 'John',
age: 30
});
// 数组
const todos = observable(['Learn MobX', 'Build App']);
// Map
const userMap = observable.map({ id: 1, name: 'John' });
// Set
const tags = observable.set(['react', 'mobx']);
observable.box #
对于基本类型值,可以使用 observable.box:
javascript
import { observable } from 'mobx';
const count = observable.box(0);
const name = observable.box('MobX');
// 读取值
console.log(count.get()); // 0
console.log(name.get()); // 'MobX'
// 修改值
count.set(1);
name.set('MobX 6');
observable.object #
创建可观察对象:
javascript
import { observable } from 'mobx';
const state = observable.object({
count: 0,
name: 'MobX'
}, {}, { deep: true });
console.log(state.count); // 0
state.count = 1;
observable.array #
创建可观察数组:
javascript
import { observable } from 'mobx';
const list = observable.array([1, 2, 3]);
// 普通数组方法
list.push(4);
list.pop();
// MobX 特有方法
list.clear(); // 清空数组
list.replace([5, 6]); // 替换数组内容
list.remove(5); // 移除元素
Observable选项 #
deep选项 #
默认情况下,observable 会递归地将嵌套对象变为可观察:
javascript
import { observable } from 'mobx';
// deep: true(默认)
const state = observable({
user: {
profile: {
name: 'John'
}
}
});
// 所有嵌套对象都是可观察的
state.user.profile.name = 'Jane'; // 响应式更新
shallow选项 #
使用 observable.shallow 只让第一层变为可观察:
javascript
import { observable } from 'mobx';
const state = observable.shallow({
users: [{ name: 'John' }, { name: 'Jane' }]
});
// users 数组是可观察的
state.users.push({ name: 'Bob' }); // 触发更新
// 但数组内的对象不是可观察的
state.users[0].name = 'Johnny'; // 不触发更新
ref选项 #
使用 observable.ref 只追踪引用,不追踪内容:
javascript
import { observable } from 'mobx';
const state = observable.ref({
data: { value: 1 }
});
// 只有 data 引用变化才触发更新
state.data = { value: 2 }; // 触发更新
state.data.value = 3; // 不触发更新
常见使用场景 #
场景一:简单状态 #
javascript
import { observable, autorun } from 'mobx';
const counter = observable.box(0);
autorun(() => {
console.log(`Count: ${counter.get()}`);
});
counter.set(1); // 输出: Count: 1
counter.set(2); // 输出: Count: 2
场景二:表单状态 #
javascript
import { observable, autorun } from 'mobx';
const form = observable({
username: '',
password: '',
rememberMe: false,
get isValid() {
return this.username.length > 0 && this.password.length > 0;
}
});
autorun(() => {
console.log(`Form valid: ${form.isValid}`);
});
form.username = 'user'; // 输出: Form valid: false
form.password = 'pass'; // 输出: Form valid: true
场景三:集合管理 #
javascript
import { observable, autorun } from 'mobx';
const store = observable({
items: [],
selectedIds: new Set(),
get selectedItems() {
return this.items.filter(item => this.selectedIds.has(item.id));
}
});
autorun(() => {
console.log(`Selected: ${store.selectedItems.length} items`);
});
store.items.push({ id: 1, name: 'Item 1' });
store.selectedIds.add(1); // 输出: Selected: 1 items
Observable与普通对象的区别 #
javascript
import { observable, isObservable, autorun } from 'mobx';
// 普通对象
const plain = { count: 0 };
// Observable对象
const observed = observable({ count: 0 });
// 检查是否为可观察对象
console.log(isObservable(plain)); // false
console.log(isObservable(observed)); // true
// Observable对象会触发响应
autorun(() => {
console.log(`Observed: ${observed.count}`);
});
observed.count = 1; // 输出: Observed: 1
注意事项 #
1. 不要解构Observable对象 #
javascript
const state = observable({ a: 1, b: 2 });
// 错误:解构后失去响应性
const { a, b } = state;
// 正确:直接访问
console.log(state.a);
2. 使用toJS获取原始数据 #
javascript
import { observable, toJS } from 'mobx';
const state = observable({
users: [{ name: 'John' }]
});
// 获取原始 JavaScript 对象
const plainObject = toJS(state);
console.log(plainObject);
3. 避免直接修改嵌套对象 #
javascript
const state = observable({
user: { name: 'John' }
});
// 可以工作,但推荐使用 action
state.user.name = 'Jane';
// 更好的方式
class Store {
state = observable({
user: { name: 'John' }
});
updateName(name) {
this.state.user.name = name;
}
}
完整示例 #
javascript
import { observable, autorun, toJS } from 'mobx';
// 创建可观察状态
const appState = observable({
// 基本类型
count: 0,
message: 'Hello',
// 数组
todos: [],
// 对象
user: {
name: '',
email: ''
},
// 计算属性
get todoCount() {
return this.todos.length;
},
get completedCount() {
return this.todos.filter(t => t.completed).length;
}
});
// 自动响应
autorun(() => {
console.log(`Todos: ${appState.todoCount}, Completed: ${appState.completedCount}`);
});
// 修改状态
appState.todos.push({ id: 1, title: 'Learn MobX', completed: false });
appState.todos[0].completed = true;
appState.user.name = 'John';
// 获取原始数据
console.log(toJS(appState));
总结 #
| 方法 | 用途 | 特点 |
|---|---|---|
observable() |
创建可观察对象 | 递归深度观察 |
observable.box() |
创建可观察基本值 | 需要get/set |
observable.shallow() |
浅层观察 | 只观察第一层 |
observable.ref() |
引用观察 | 只追踪引用 |
继续学习 makeObservable,了解如何在类中配置响应式状态。
最后更新:2026-03-28