工具函数 #

MobX 提供了一系列实用工具函数,帮助开发者更好地处理可观察状态、调试和类型检查。

toJS #

将可观察对象转换为普通 JavaScript 对象。

基本用法 #

javascript
import { makeAutoObservable, toJS } from 'mobx';

class Store {
  items = [{ name: 'Item 1' }, { name: 'Item 2' }];
  user = { name: 'John', age: 30 };

  constructor() {
    makeAutoObservable(this);
  }
}

const store = new Store();

// 转换为普通对象
const plainItems = toJS(store.items);
const plainUser = toJS(store.user);

console.log(plainItems);
// [{ name: 'Item 1' }, { name: 'Item 2' }]

console.log(plainUser);
// { name: 'John', age: 30 }

使用场景 #

javascript
import { toJS } from 'mobx';

// 1. 发送到服务器
async function saveData() {
  const plainData = toJS(store.data);
  await fetch('/api/save', {
    method: 'POST',
    body: JSON.stringify(plainData)
  });
}

// 2. 深拷贝
const copy = toJS(store.complexObject);

// 3. 比较
const isEqual = JSON.stringify(toJS(obj1)) === JSON.stringify(toJS(obj2));

// 4. 日志
console.log('State:', toJS(store));

isObservable #

检查对象是否为可观察对象。

基本用法 #

javascript
import { isObservable, makeAutoObservable, observable } from 'mobx';

const plainObject = { count: 0 };
const observableObject = observable({ count: 0 });

console.log(isObservable(plainObject));       // false
console.log(isObservable(observableObject));  // true

相关检查函数 #

javascript
import {
  isObservable,
  isObservableObject,
  isObservableArray,
  isObservableMap,
  isObservableSet,
  isBoxedObservable,
  isObservableProp,
  isComputed,
  isAction,
  makeAutoObservable
} from 'mobx';

class Store {
  items = [];
  user = new Map();
  tags = new Set();

  get count() {
    return this.items.length;
  }

  addItem() {
    this.items.push({});
  }

  constructor() {
    makeAutoObservable(this);
  }
}

const store = new Store();

// 检查整体
isObservable(store);        // true

// 检查类型
isObservableObject(store);  // true
isObservableArray(store.items);  // true
isObservableMap(store.user);     // true
isObservableSet(store.tags);     // true

// 检查属性
isObservableProp(store, 'items');  // true
isComputed(store, 'count');        // true
isAction(store, 'addItem');        // true

extendObservable #

向现有对象添加可观察属性。

基本用法 #

javascript
import { extendObservable } from 'mobx';

const user = { name: 'John' };

// 添加可观察属性
extendObservable(user, {
  age: 30,
  get displayName() {
    return `${this.name} (${this.age})`;
  }
});

user.age = 31;  // 响应式更新

使用场景 #

javascript
import { extendObservable, autorun } from 'mobx';

// 动态添加属性
class DynamicStore {
  constructor() {
    extendObservable(this, {
      count: 0,
      increment() {
        this.count++;
      }
    });
  }
}

const store = new DynamicStore();

autorun(() => {
  console.log('Count:', store.count);
});

store.increment();

observable.box #

创建可观察的基本类型值。

基本用法 #

javascript
import { observable, autorun } 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');

// 响应式
autorun(() => {
  console.log('Count:', count.get());
});

count.set(2);  // 输出: Count: 2

使用场景 #

javascript
import { observable, computed } from 'mobx';

// 简单状态
const loading = observable.box(false);

// 切换状态
function toggleLoading() {
  loading.set(!loading.get());
}

// 计算值
const status = computed(() => loading.get() ? 'Loading...' : 'Ready');

// 观察变化
import { observe } from 'mobx';

observe(loading, (change) => {
  console.log(`Loading changed from ${change.oldValue} to ${change.newValue}`);
});

observe #

观察可观察对象的变化。

基本用法 #

javascript
import { observe, makeAutoObservable } from 'mobx';

class Store {
  count = 0;
  items = [];

  constructor() {
    makeAutoObservable(this);
  }
}

const store = new Store();

// 观察属性变化
const dispose = observe(store, 'count', (change) => {
  console.log(`count: ${change.oldValue} -> ${change.newValue}`);
});

store.count = 1;  // 输出: count: 0 -> 1

// 清除观察
dispose();

观察数组变化 #

javascript
import { observe, observable } from 'mobx';

const items = observable([1, 2, 3]);

observe(items, (change) => {
  console.log('Array changed:', change);
  // change.type: 'splice' | 'update'
  // change.added: 添加的元素
  // change.removed: 删除的元素
  // change.index: 变化的索引
});

items.push(4);  // 触发观察

观察Map变化 #

javascript
import { observe, observable } from 'mobx';

const map = observable.map({ a: 1 });

observe(map, (change) => {
  console.log('Map changed:', change);
  // change.type: 'add' | 'update' | 'delete'
  // change.name: 键名
  // change.newValue: 新值
  // change.oldValue: 旧值
});

map.set('b', 2);  // 触发观察

computed和autorun的变体 #

computed.struct #

结构比较的计算值:

javascript
import { computed, makeAutoObservable } from 'mobx';

class Store {
  x = 0;
  y = 0;

  constructor() {
    makeAutoObservable(this, {
      position: computed.struct
    });
  }

  get position() {
    return { x: this.x, y: this.y };
  }
}

const store = new Store();

// 普通 computed:每次返回新对象,会触发更新
// computed.struct:结构相同则不触发更新

store.x = 0;  // position 返回 { x: 0, y: 0 }
store.x = 0;  // position 仍返回 { x: 0, y: 0 },不触发更新

autorun的选项 #

javascript
import { autorun } from 'mobx';

// 延迟执行
autorun(
  () => {
    console.log(store.count);
  },
  { delay: 300 }  // 防抖
);

// 自定义调度器
autorun(
  () => {
    console.log(store.count);
  },
  {
    scheduler: (run) => {
      requestAnimationFrame(run);
    }
  }
);

// 设置名称(调试用)
autorun(
  () => {
    console.log(store.count);
  },
  { name: 'countLogger' }
);

其他工具函数 #

transaction #

批量更新(已弃用,使用 action 替代):

javascript
import { transaction, makeAutoObservable } from 'mobx';

// 推荐使用 action
class Store {
  a = 0;
  b = 0;

  constructor() {
    makeAutoObservable(this);
  }

  updateBoth(a, b) {
    this.a = a;
    this.b = b;
    // action 自动批量更新
  }
}

untracked #

在追踪上下文中不追踪某些访问:

javascript
import { untracked, autorun, makeAutoObservable } from 'mobx';

class Store {
  count = 0;
  debug = true;

  constructor() {
    makeAutoObservable(this);
  }
}

const store = new Store();

autorun(() => {
  // 不追踪 debug 的变化
  const shouldLog = untracked(() => store.debug);

  if (shouldLog) {
    console.log('Count:', store.count);
  }
});

store.debug = false;  // 不会触发 autorun
store.count = 1;      // 会触发 autorun

spy #

全局监听所有 MobX 事件:

javascript
import { spy } from 'mobx';

// 启用全局监听
const dispose = spy((event) => {
  if (event.type === 'action') {
    console.log(`Action: ${event.name}`, event);
  }
});

// 清除监听
dispose();

完整示例 #

调试工具 #

javascript
import { spy, toJS, isObservable } from 'mobx';

// 开发环境启用调试
if (process.env.NODE_ENV === 'development') {
  spy((event) => {
    if (event.type === 'action') {
      console.group(`Action: ${event.name}`);
      console.log('Arguments:', event.arguments);
      console.log('Target:', event.target);
      console.groupEnd();
    }
  });
}

// 状态快照
function getSnapshot(store) {
  if (!isObservable(store)) {
    return store;
  }
  return toJS(store);
}

// 状态比较
function compareState(store1, store2) {
  return JSON.stringify(getSnapshot(store1)) === JSON.stringify(getSnapshot(store2));
}

持久化工具 #

javascript
import { toJS, autorun, makeAutoObservable } from 'mobx';

function persist(store, key, storage = localStorage) {
  // 恢复状态
  const saved = storage.getItem(key);
  if (saved) {
    try {
      const data = JSON.parse(saved);
      Object.assign(store, data);
    } catch (e) {
      console.error('Failed to restore state:', e);
    }
  }

  // 自动保存
  autorun(() => {
    storage.setItem(key, JSON.stringify(toJS(store)));
  });
}

// 使用
class UserStore {
  name = '';
  email = '';

  constructor() {
    makeAutoObservable(this);
    persist(this, 'user-store');
  }
}

总结 #

函数 用途
toJS 转换为普通对象
isObservable 检查是否可观察
extendObservable 添加可观察属性
observable.box 创建可观察基本值
observe 观察变化
untracked 不追踪访问
spy 全局监听

继续学习 项目结构,了解 MobX 项目的最佳组织方式。

最后更新:2026-03-28