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