5月27日 18:11

MobX 6 有哪些主要变化和新特性?

MobX 6 最核心的变化有三个:强制 action 修改状态、引入 makeObservable/makeAutoObservable 替代装饰器、Proxy 成为底层实现。装饰器仍然支持但不再是推荐方式,配合 mobx-undecorate 工具可以一键迁移旧代码。

追问

makeObservable 和 makeAutoObservable 有什么区别?

makeObservable 需要你手动标注每个成员的类型(observable、computed、action),适合需要精细控制的场景。makeAutoObservable 自动推断:getter 标记为 computed,方法标记为 action,其余字段标记为 observable。但 makeAutoObservable 不能用于子类,也不能标注被忽略的字段——这种时候用 makeObservable。

javascript
class Store { count = 0; constructor() { // 二选一 makeObservable(this, { count: observable, doubled: computed, increment: action }); // 或者 makeAutoObservable(this); } get doubled() { return this.count * 2; } increment() { this.count++; } }

为什么 MobX 6 强制要求在 action 中修改状态?

MobX 5 可以在 action 外部直接修改 observable,这导致状态变更难以追踪,调试时无法定位是哪段代码改了数据。MobX 6 默认 enforceActions: "always",所有状态修改必须在 action 内进行,这样每次状态变更都有明确的调用栈,DevTools 也能清晰展示变更来源。如果迁移时不想立刻改,可以临时配置 enforceActions: "never" 回退到旧行为。

装饰器为什么不再是推荐方式?

TC39 装饰器提案经历了多次语法变更,Legacy Decorators(Babel experimentalDecorators)一直不是标准。MobX 6 选择拥抱标准:用 makeObservable 在 constructor 中声明式标注成员类型,这在任何 JS 环境下都能运行,不需要 Babel 插件或 TypeScript 实验性配置。如果你仍想用装饰器,MobX 6 也支持,但需要在 constructor 里补一句 makeObservable(this) 才能生效。

MobX 5 升级到 6 的迁移步骤是什么?

  1. 先升级到 MobX 5 的最新小版本,解决所有废弃警告
  2. 安装 MobX 6,运行 npx mobx-undecorate 自动迁移代码
  3. TypeScript 项目设置 useDefineForClassFields: true;Babel 项目设置 ["@babel/plugin-proposal-class-properties", { "loose": false }]
  4. 每个有 MobX 成员的类,在 constructor 中调用 makeObservable(this) 或 makeAutoObservable(this)
  5. 用 configure({ enforceActions: "always" }) 启用严格模式
  6. 替换已移除的 API:decorate() 用 makeObservable 替代,isObservableObject 用 isObservable 替代

Proxy 在 MobX 6 中扮演什么角色?

MobX 5 默认也用 Proxy,但可以降级到 getter/setter 实现。MobX 6 将 Proxy 作为唯一的响应式实现(IE 和旧版 React Native 除外,需配置 useProxies: "never")。Proxy 的好处是能拦截更多操作(如动态添加属性),Observable 对象的行为更接近普通对象,不需要额外的 API 来处理属性增删。

写段代码

javascript
import { makeAutoObservable } from "mobx"; class TodoStore { todos = []; constructor() { makeAutoObservable(this); } get pending() { return this.todos.filter(t => !t.done); } addTodo(text) { this.todos.push({ text, done: false }); } toggle(id) { this.todos[id].done = !this.todos[id].done; } }
标签:Mobx