乐闻世界logo
搜索文章和话题

MobX 6 相比 MobX 4/5 有哪些重要变化?

2月22日 14:08

MobX 6 是 MobX 的最新主要版本,相比 MobX 4/5 有许多重要的变化和改进。了解这些变化对于升级和维护项目非常重要。

主要变化

1. 移除装饰器支持

MobX 6 默认不再支持装饰器语法,推荐使用 makeObservablemakeAutoObservable

MobX 4/5(装饰器语法):

javascript
import { observable, action, computed } from 'mobx'; class TodoStore { @observable todos = []; @observable filter = 'all'; @computed get completedTodos() { return this.todos.filter(todo => todo.completed); } @action addTodo(text) { this.todos.push({ text, completed: false }); } }

MobX 6(推荐方式):

javascript
import { makeAutoObservable } from 'mobx'; class TodoStore { todos = []; filter = 'all'; constructor() { makeAutoObservable(this); } get completedTodos() { return this.todos.filter(todo => todo.completed); } addTodo(text) { this.todos.push({ text, completed: false }); } }

2. makeObservable 和 makeAutoObservable

MobX 6 引入了两个新的 API 来替代装饰器:

makeObservable

需要显式指定每个属性的类型。

javascript
import { makeObservable, observable, action, computed } from 'mobx'; class TodoStore { todos = []; filter = 'all'; constructor() { makeObservable(this, { todos: observable, filter: observable, completedTodos: computed, addTodo: action }); } get completedTodos() { return this.todos.filter(todo => todo.completed); } addTodo(text) { this.todos.push({ text, completed: false }); } }

makeAutoObservable(推荐)

自动推断属性类型,更简洁。

javascript
import { makeAutoObservable } from 'mobx'; class TodoStore { todos = []; filter = 'all'; constructor() { makeAutoObservable(this); } get completedTodos() { return this.todos.filter(todo => todo.completed); } addTodo(text) { this.todos.push({ text, completed: false }); } }

3. 移除 configure

MobX 6 移除了 configure API,不再需要全局配置。

MobX 4/5:

javascript
import { configure } from 'mobx'; configure({ enforceActions: 'always', useProxies: 'ifavailable' });

MobX 6:

javascript
// 不再需要 configure,默认行为已经优化

4. 移除 extras

MobX 6 移除了 extras API,相关功能被整合到主 API 中。

MobX 4/5:

javascript
import { extras } from 'mobx'; const isObservable = extras.isObservable(obj);

MobX 6:

javascript
import { isObservable } from 'mobx'; const isObservable = isObservable(obj);

5. 移除 intercept 和 observe

MobX 6 移除了 interceptobserve API,推荐使用 reaction 替代。

MobX 4/5:

javascript
import { observe } from 'mobx'; const disposer = observe(store.todos, (change) => { console.log('Todo changed:', change); });

MobX 6:

javascript
import { reaction } from 'mobx'; const disposer = reaction( () => store.todos.length, (length) => { console.log('Todo count changed:', length); } );

6. 类型推断改进

MobX 6 对 TypeScript 的支持更好,类型推断更准确。

typescript
import { makeAutoObservable } from 'mobx'; class TodoStore { todos: Todo[] = []; filter: 'all' | 'completed' | 'active' = 'all'; constructor() { makeAutoObservable<TodoStore>(this); } get completedTodos(): Todo[] { return this.todos.filter(todo => todo.completed); } addTodo(text: string): void { this.todos.push({ text, completed: false }); } }

7. 移除 mobx-react 的 inject 和 Provider

MobX 6 推荐使用 React Context API,不再需要 injectProvider

MobX 4/5:

javascript
import { Provider, inject, observer } from 'mobx-react'; @inject('todoStore') @observer class TodoList extends React.Component { render() { const { todoStore } = this.props; return <div>{/* ... */}</div>; } } function App() { return ( <Provider todoStore={todoStore}> <TodoList /> </Provider> ); }

MobX 6:

javascript
import { observer } from 'mobx-react-lite'; import { createContext, useContext } from 'react'; const TodoContext = createContext(null); function TodoProvider({ children, store }) { return ( <TodoContext.Provider value={store}> {children} </TodoContext.Provider> ); } function useTodoStore() { const store = useContext(TodoContext); if (!store) { throw new Error('useTodoStore must be used within TodoProvider'); } return store; } const TodoList = observer(() => { const store = useTodoStore(); return <div>{/* ... */}</div>; }); function App() { return ( <TodoProvider store={todoStore}> <TodoList /> </TodoProvider> ); }

8. 性能改进

MobX 6 在性能方面有许多改进:

  1. 更小的包体积:通过 Tree-shaking 减少包体积
  2. 更快的响应速度:优化了依赖追踪算法
  3. 更好的内存管理:减少了内存占用

9. 错误处理改进

MobX 6 提供了更清晰的错误信息。

javascript
// MobX 6 会提供更清晰的错误信息 class Store { data = []; constructor() { makeAutoObservable(this); } // 如果在 action 外修改状态 modifyData() { this.data.push({}); // 警告:在 action 外修改状态 } }

迁移指南

从 MobX 4/5 迁移到 MobX 6

1. 移除装饰器

之前:

javascript
class Store { @observable data = []; @action addData(item) { this.data.push(item); } }

之后:

javascript
class Store { data = []; constructor() { makeAutoObservable(this); } addData(item) { this.data.push(item); } }

2. 更新 mobx-react

之前:

javascript
import { Provider, inject, observer } from 'mobx-react'; @inject('store') @observer class Component extends React.Component { render() { const { store } = this.props; return <div>{store.data}</div>; } }

之后:

javascript
import { observer } from 'mobx-react-lite'; const Component = observer(() => { const store = useStore(); return <div>{store.data}</div>; });

3. 移除 configure

之前:

javascript
import { configure } from 'mobx'; configure({ enforceActions: 'always' });

之后:

javascript
// 不再需要 configure

4. 更新 extras

之前:

javascript
import { extras } from 'mobx'; if (extras.isObservable(obj)) { // ... }

之后:

javascript
import { isObservable } from 'mobx'; if (isObservable(obj)) { // ... }

最佳实践

1. 使用 makeAutoObservable

javascript
class Store { data = []; constructor() { makeAutoObservable(this); } }

2. 使用 mobx-react-lite

javascript
import { observer } from 'mobx-react-lite'; const Component = observer(() => { return <div>{/* ... */}</div>; });

3. 使用 React Context

javascript
const StoreContext = createContext(null); function StoreProvider({ children, store }) { return ( <StoreContext.Provider value={store}> {children} </StoreContext.Provider> ); } function useStore() { const store = useContext(StoreContext); if (!store) { throw new Error('useStore must be used within StoreProvider'); } return store; }

4. 使用 TypeScript

typescript
class Store { data: Data[] = []; constructor() { makeAutoObservable<Store>(this); } }

常见问题

1. 如何继续使用装饰器?

如果需要继续使用装饰器,可以安装 mobx-undecorate 包。

javascript
import { decorate, observable, action } from 'mobx'; class Store { data = []; addData(item) { this.data.push(item); } } decorate(Store, { data: observable, addData: action });

2. 如何处理类型推断?

使用 makeAutoObservable 时,可以传入泛型参数。

typescript
class Store { data: Data[] = []; constructor() { makeAutoObservable<Store>(this); } }

3. 如何处理 action.bound?

使用 action.bound 时,需要在 makeObservable 中指定。

javascript
class Store { data = []; constructor() { makeObservable(this, { data: observable, addData: action.bound }); } addData(item) { this.data.push(item); } }

总结

  • MobX 6 移除了装饰器支持,推荐使用 makeAutoObservable
  • 移除了 configureextrasinterceptobserve 等 API
  • 推荐使用 mobx-react-lite 和 React Context
  • 对 TypeScript 的支持更好
  • 性能和错误处理都有改进
  • 迁移相对简单,主要是替换装饰器语法
标签:Mobx