makeAutoObservable #

makeAutoObservable 是 MobX 6 引入的一个便捷方法,它可以自动推断并配置对象的响应式属性,大大简化了代码。

基本用法 #

对比makeObservable #

javascript
// 使用 makeObservable - 需要显式配置
import { makeObservable, observable, action, computed } from 'mobx';

class Counter {
  count = 0;

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

  increment() {
    this.count++;
  }

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

// 使用 makeAutoObservable - 自动推断
import { makeAutoObservable } from 'mobx';

class Counter {
  count = 0;

  constructor() {
    makeAutoObservable(this);
  }

  increment() {
    this.count++;
  }

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

自动推断规则 #

makeAutoObservable 根据以下规则自动推断:

成员类型 推断结果
普通属性 observable
getter computed
方法 action
生成器方法 flow
javascript
import { makeAutoObservable } from 'mobx';

class Store {
  // 自动变为 observable
  count = 0;
  name = 'MobX';
  items = [];

  // 自动变为 computed
  get double() {
    return this.count * 2;
  }

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

  // 自动变为 action
  increment() {
    this.count++;
  }

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

  constructor() {
    makeAutoObservable(this);
  }
}

配置选项 #

excludes #

排除不需要自动配置的属性:

javascript
import { makeAutoObservable } from 'mobx';

class Store {
  count = 0;
  helper = 'not reactive';  // 不需要响应式

  constructor() {
    makeAutoObservable(this, {
      helper: false  // 排除
    });
  }

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

overrides #

覆盖自动推断的类型:

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

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

  constructor() {
    makeAutoObservable(this, {
      // 使用 shallow 而不是默认的 deep
      items: observable.shallow,

      // 自动绑定 this
      increment: action.bound,

      // 使用结构比较
      summary: computed.struct
    });
  }

  increment() {
    this.count++;
  }

  get summary() {
    return { count: this.count, total: this.items.length };
  }
}

autoBind #

自动绑定所有方法的 this

javascript
import { makeAutoObservable } from 'mobx';

class Store {
  count = 0;

  constructor() {
    makeAutoObservable(this, {}, { autoBind: true });
  }

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

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

deep选项 #

控制嵌套对象的观察深度:

javascript
import { makeAutoObservable } from 'mobx';

class Store {
  constructor() {
    makeAutoObservable(this, {}, { deep: true });
  }

  user = {
    profile: {
      name: 'John'
    }
  };
}

完整示例 #

购物车Store #

javascript
import { makeAutoObservable } from 'mobx';

class CartStore {
  items = [];
  discount = 0;

  constructor() {
    makeAutoObservable(this, {}, { autoBind: true });
  }

  // Actions
  addItem(product, quantity = 1) {
    const existingItem = this.items.find(item => item.id === product.id);

    if (existingItem) {
      existingItem.quantity += quantity;
    } else {
      this.items.push({
        id: product.id,
        name: product.name,
        price: product.price,
        quantity
      });
    }
  }

  removeItem(productId) {
    this.items = this.items.filter(item => item.id !== productId);
  }

  updateQuantity(productId, quantity) {
    const item = this.items.find(item => item.id === productId);
    if (item) {
      if (quantity <= 0) {
        this.removeItem(productId);
      } else {
        item.quantity = quantity;
      }
    }
  }

  setDiscount(discount) {
    this.discount = Math.max(0, Math.min(100, discount));
  }

  clearCart() {
    this.items = [];
    this.discount = 0;
  }

  // Computed
  get subtotal() {
    return this.items.reduce(
      (sum, item) => sum + item.price * item.quantity,
      0
    );
  }

  get discountAmount() {
    return this.subtotal * (this.discount / 100);
  }

  get total() {
    return this.subtotal - this.discountAmount;
  }

  get itemCount() {
    return this.items.reduce((sum, item) => sum + item.quantity, 0);
  }

  get isEmpty() {
    return this.items.length === 0;
  }
}

export default new CartStore();

表单Store #

javascript
import { makeAutoObservable } from 'mobx';

class FormStore {
  values = {};
  errors = {};
  touched = {};
  isSubmitting = false;

  constructor(initialValues = {}) {
    this.values = initialValues;
    makeAutoObservable(this);
  }

  // Actions
  setField(name, value) {
    this.values[name] = value;
    this.validateField(name);
  }

  setTouched(name) {
    this.touched[name] = true;
  }

  setError(name, error) {
    this.errors[name] = error;
  }

  clearError(name) {
    delete this.errors[name];
  }

  setSubmitting(isSubmitting) {
    this.isSubmitting = isSubmitting;
  }

  reset() {
    this.values = {};
    this.errors = {};
    this.touched = {};
    this.isSubmitting = false;
  }

  validateField(name) {
    const value = this.values[name];

    switch (name) {
      case 'email':
        if (!value) {
          this.setError(name, 'Email is required');
        } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
          this.setError(name, 'Invalid email format');
        } else {
          this.clearError(name);
        }
        break;

      case 'password':
        if (!value) {
          this.setError(name, 'Password is required');
        } else if (value.length < 8) {
          this.setError(name, 'Password must be at least 8 characters');
        } else {
          this.clearError(name);
        }
        break;

      default:
        if (!value) {
          this.setError(name, `${name} is required`);
        } else {
          this.clearError(name);
        }
    }
  }

  validateAll() {
    Object.keys(this.values).forEach(name => {
      this.validateField(name);
    });
    return this.isValid;
  }

  // Computed
  get isValid() {
    return Object.keys(this.errors).length === 0;
  }

  get isDirty() {
    return Object.keys(this.touched).length > 0;
  }

  get hasErrors() {
    return Object.keys(this.errors).length > 0;
  }
}

export default FormStore;

异步数据Store #

javascript
import { makeAutoObservable } from 'mobx';

class AsyncStore {
  data = null;
  loading = false;
  error = null;

  constructor() {
    makeAutoObservable(this);
  }

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

  setData(data) {
    this.data = data;
    this.error = null;
  }

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

  clear() {
    this.data = null;
    this.error = null;
  }

  async fetchData(url) {
    this.loading = true;
    this.error = null;

    try {
      const response = await fetch(url);
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      const data = await response.json();
      this.setData(data);
      return data;
    } catch (error) {
      this.setError(error.message);
      throw error;
    } finally {
      this.loading = false;
    }
  }

  // Computed
  get hasData() {
    return this.data !== null;
  }

  get hasError() {
    return this.error !== null;
  }

  get status() {
    if (this.loading) return 'loading';
    if (this.error) return 'error';
    if (this.data) return 'success';
    return 'idle';
  }
}

export default AsyncStore;

使用注意事项 #

1. 继承限制 #

makeAutoObservable 在继承场景下有限制:

javascript
// 不推荐:继承中使用 makeAutoObservable
class BaseStore {
  count = 0;
  constructor() {
    makeAutoObservable(this);
  }
}

class ExtendedStore extends BaseStore {
  name = '';
  constructor() {
    super();
    // 问题:父类已经调用过 makeAutoObservable
  }
}

// 推荐:使用 makeObservable 处理继承
class BaseStore {
  count = 0;
  constructor() {
    makeObservable(this, {
      count: observable
    });
  }
}

class ExtendedStore extends BaseStore {
  name = '';
  constructor() {
    super();
    makeObservable(this, {
      name: observable
    });
  }
}

2. 静态成员 #

静态成员不会被处理:

javascript
class Store {
  static instance = null;  // 不会被处理

  count = 0;

  constructor() {
    makeAutoObservable(this);
  }
}

3. 私有字段 #

私有字段(#开头)不会被处理:

javascript
class Store {
  #privateField = 'secret';  // 不会被处理

  count = 0;

  constructor() {
    makeAutoObservable(this);
  }
}

4. 函数属性 #

箭头函数属性会被当作 action:

javascript
class Store {
  count = 0;

  // 这是一个 action
  increment = () => {
    this.count++;
  };

  constructor() {
    makeAutoObservable(this);
  }
}

makeAutoObservable vs makeObservable #

选择指南:

场景 推荐使用
新项目 makeAutoObservable
简单 Store makeAutoObservable
需要精细控制 makeObservable
复杂继承结构 makeObservable
需要特殊配置 makeObservable

总结 #

makeAutoObservable 的优势:

  • 代码简洁:无需手动配置
  • 自动推断:智能识别成员类型
  • 开发效率高:减少样板代码

配置选项总结:

选项 说明
excludes 排除属性
overrides 覆盖推断类型
autoBind 自动绑定this
deep 深度观察

继续学习 Action动作,了解如何安全地修改状态。

最后更新:2026-03-28