makeObservable #

makeObservable 是 MobX 提供的一个函数,用于在类中显式地标记哪些属性是可观察的、哪些方法是动作、哪些属性是计算值。

基本用法 #

简单示例 #

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

class Counter {
  // 可观察状态
  count = 0;

  constructor() {
    // 配置响应式
    makeObservable(this, {
      count: observable,
      increment: action,
      decrement: action,
      double: computed
    });
  }

  // 动作
  increment() {
    this.count++;
  }

  decrement() {
    this.count--;
  }

  // 计算值
  get double() {
    return this.count * 2;
  }
}

注解类型 #

MobX 提供了多种注解类型:

observable #

标记属性为可观察状态:

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

class Store {
  constructor() {
    makeObservable(this, {
      // 基本类型
      count: observable,
      name: observable,

      // 对象
      user: observable,

      // 数组
      items: observable
    });
  }

  count = 0;
  name = '';
  user = {};
  items = [];
}

observable的变体 #

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

class Store {
  constructor() {
    makeObservable(this, {
      // 深度观察(默认)
      deepObject: observable,

      // 浅层观察
      shallowArray: observable.shallow,

      // 引用观察
      refValue: observable.ref,

      // 结构观察
      structValue: observable.struct
    });
  }

  deepObject = { nested: { value: 1 } };
  shallowArray = [{ id: 1 }];
  refValue = { data: 'test' };
  structValue = { x: 0, y: 0 };
}

action #

标记方法为动作:

javascript
import { makeObservable, observable, action } from 'mobx';

class Store {
  count = 0;

  constructor() {
    makeObservable(this, {
      count: observable,
      increment: action,
      decrement: action,
      reset: action.bound  // 自动绑定this
    });
  }

  increment() {
    this.count++;
  }

  decrement() {
    this.count--;
  }

  reset() {
    this.count = 0;
  }
}

action.bound #

自动绑定 this

javascript
import { makeObservable, observable, action } from 'mobx';

class Store {
  count = 0;

  constructor() {
    makeObservable(this, {
      count: observable,
      increment: action.bound
    });
  }

  increment() {
    this.count++;
  }
}

const store = new Store();
const { increment } = store;
increment();  // this 正确绑定

computed #

标记 getter 为计算值:

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

class TodoStore {
  todos = [];

  constructor() {
    makeObservable(this, {
      todos: observable,
      completedCount: computed,
      activeCount: computed,
      totalCount: computed
    });
  }

  get completedCount() {
    return this.todos.filter(t => t.completed).length;
  }

  get activeCount() {
    return this.todos.filter(t => !t.completed).length;
  }

  get totalCount() {
    return this.todos.length;
  }
}

computed的变体 #

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

class Store {
  position = { x: 0, y: 0 };

  constructor() {
    makeObservable(this, {
      position: observable,
      // 结构比较,避免不必要的更新
      normalizedPosition: computed.struct
    });
  }

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

override #

覆盖继承的属性:

javascript
import { makeObservable, observable, action, override } from 'mobx';

class BaseStore {
  count = 0;

  constructor() {
    makeObservable(this, {
      count: observable,
      increment: action
    });
  }

  increment() {
    this.count++;
  }
}

class ExtendedStore extends BaseStore {
  constructor() {
    super();
    makeObservable(this, {
      increment: override  // 覆盖父类方法
    });
  }

  increment() {
    this.count += 2;  // 不同的实现
  }
}

完整示例 #

Todo Store #

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

class TodoStore {
  // 状态
  todos = [];
  filter = 'all';

  constructor() {
    makeObservable(this, {
      // 状态
      todos: observable,
      filter: observable,

      // 动作
      addTodo: action,
      removeTodo: action,
      toggleTodo: action,
      setFilter: action.bound,
      clearCompleted: action,

      // 计算值
      filteredTodos: computed,
      completedCount: computed,
      activeCount: computed
    });
  }

  // 动作
  addTodo(title) {
    this.todos.push({
      id: Date.now(),
      title,
      completed: false
    });
  }

  removeTodo(id) {
    this.todos = this.todos.filter(t => t.id !== id);
  }

  toggleTodo(id) {
    const todo = this.todos.find(t => t.id === id);
    if (todo) {
      todo.completed = !todo.completed;
    }
  }

  setFilter(filter) {
    this.filter = filter;
  }

  clearCompleted() {
    this.todos = this.todos.filter(t => !t.completed);
  }

  // 计算值
  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;
  }
}

export default new TodoStore();

用户 Store #

javascript
import { makeObservable, observable, action, computed, flow } from 'mobx';

class UserStore {
  users = [];
  currentUser = null;
  loading = false;
  error = null;

  constructor() {
    makeObservable(this, {
      // 状态
      users: observable,
      currentUser: observable,
      loading: observable,
      error: observable,

      // 动作
      setUser: action,
      clearUser: action,
      setLoading: action.bound,
      setError: action,

      // 异步动作
      fetchUsers: flow,
      login: flow,

      // 计算值
      isLoggedIn: computed,
      userCount: computed
    });
  }

  // 同步动作
  setUser(user) {
    this.currentUser = user;
    this.error = null;
  }

  clearUser() {
    this.currentUser = null;
  }

  setLoading(loading) {
    this.loading = loading;
  }

  setError(error) {
    this.error = error;
  }

  // 异步动作(使用 flow)
  *fetchUsers() {
    this.loading = true;
    try {
      const response = yield fetch('/api/users');
      const users = yield response.json();
      this.users = users;
      this.error = null;
    } catch (error) {
      this.error = error.message;
    } finally {
      this.loading = false;
    }
  }

  *login(credentials) {
    this.loading = true;
    try {
      const response = yield fetch('/api/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(credentials)
      });
      const user = yield response.json();
      this.currentUser = user;
      this.error = null;
    } catch (error) {
      this.error = error.message;
    } finally {
      this.loading = false;
    }
  }

  // 计算值
  get isLoggedIn() {
    return this.currentUser !== null;
  }

  get userCount() {
    return this.users.length;
  }
}

export default new UserStore();

使用装饰器(可选) #

如果你配置了装饰器支持,可以使用更简洁的语法:

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

class Store {
  @observable count = 0;
  @observable name = '';

  @action
  increment() {
    this.count++;
  }

  @action.bound
  reset() {
    this.count = 0;
  }

  @computed
  get double() {
    return this.count * 2;
  }

  constructor() {
    makeObservable(this);
  }
}

makeObservable vs makeAutoObservable #

特性 makeObservable makeAutoObservable
配置方式 显式配置 自动推断
灵活性
代码量
继承支持 有限
javascript
// makeObservable - 显式配置
class Store1 {
  count = 0;
  constructor() {
    makeObservable(this, {
      count: observable,
      increment: action
    });
  }
  increment() { this.count++; }
}

// makeAutoObservable - 自动推断
class Store2 {
  count = 0;
  constructor() {
    makeAutoObservable(this);
  }
  increment() { this.count++; }
}

总结 #

makeObservable 提供了精细的响应式配置控制:

注解 用途
observable 可观察状态
observable.shallow 浅层观察
observable.ref 引用观察
action 动作方法
action.bound 自动绑定this
computed 计算值
computed.struct 结构比较的计算值
override 覆盖继承成员

继续学习 makeAutoObservable,了解更简洁的自动配置方式。

最后更新:2026-03-28