Observable状态 #

Observable(可观察)是 MobX 响应式系统的基础。通过将状态变为可观察,MobX 可以自动追踪状态的读取和修改,从而实现响应式更新。

什么是Observable? #

Observable 是一种特殊的数据结构,它允许 MobX 追踪:

  1. 读取操作:谁在读取这个值
  2. 修改操作:这个值何时被修改
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