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

MobX 中 action 的作用和使用方法是什么?

2月22日 14:06

在 MobX 中,action 是修改 observable 状态的唯一推荐方式。使用 action 可以确保状态变化是可追踪、可预测的,并且能够优化性能。

Action 的作用

  1. 批量更新:action 内部的所有状态变化会被批量处理,减少不必要的重新计算
  2. 可追踪性:所有状态变化都集中在 action 中,便于调试和追踪
  3. 事务性:action 内部的状态变化是原子的,要么全部成功,要么全部失败
  4. 性能优化:减少 reaction 的触发次数,提高性能

Action 的使用方式

1. 使用装饰器

javascript
import { observable, action } from 'mobx'; class TodoStore { @observable todos = []; @action addTodo(text) { this.todos.push({ text, completed: false }); } @action.bound removeTodo(id) { this.todos = this.todos.filter(todo => todo.id !== id); } @action async fetchTodos() { const response = await fetch('/api/todos'); const data = await response.json(); this.todos = data; } }

2. 使用 makeObservable

javascript
import { makeObservable, observable, action } from 'mobx'; class TodoStore { todos = []; constructor() { makeObservable(this, { todos: observable, addTodo: action, removeTodo: action.bound, fetchTodos: action }); } addTodo(text) { this.todos.push({ text, completed: false }); } removeTodo(id) { this.todos = this.todos.filter(todo => todo.id !== id); } async fetchTodos() { const response = await fetch('/api/todos'); const data = await response.json(); this.todos = data; } }

3. 使用 runInAction

javascript
import { observable, runInAction } from 'mobx'; class TodoStore { todos = []; async fetchTodos() { const response = await fetch('/api/todos'); const data = await response.json(); runInAction(() => { this.todos = data; }); } }

Action 的类型

1. action

最基础的 action 装饰器,用于包装状态修改方法。

javascript
@action updateTodo(id, updates) { const todo = this.todos.find(t => t.id === id); if (todo) { Object.assign(todo, updates); } }

2. action.bound

自动绑定 this 的 action,避免在回调函数中丢失 this 上下文。

javascript
@action.bound handleClick() { this.count++; } // 使用时不需要 bind <button onClick={this.handleClick}>Click</button>

3. runInAction

在异步操作中修改状态时使用。

javascript
async loadData() { const response = await fetch('/api/data'); const data = await response.json(); runInAction(() => { this.data = data; this.loading = false; }); }

Action 的最佳实践

1. 始终在 action 中修改状态

javascript
// ❌ 错误:直接修改状态 class Store { @observable count = 0; increment() { this.count++; // 不是 action } } // ✅ 正确:在 action 中修改状态 class Store { @observable count = 0; @action increment() { this.count++; } }

2. 使用 action.bound 处理事件处理器

javascript
class Component { @observable count = 0; @action.bound handleClick() { this.count++; } render() { return <button onClick={this.handleClick}>Click</button>; } }

3. 异步操作中使用 runInAction

javascript
@action async fetchUser(id) { this.loading = true; try { const response = await fetch(`/api/users/${id}`); const data = await response.json(); runInAction(() => { this.user = data; this.loading = false; }); } catch (error) { runInAction(() => { this.error = error.message; this.loading = false; }); } }

4. 合理拆分 action

javascript
// ❌ 过于复杂的 action @action handleComplexOperation(data) { this.loading = true; this.data = data; this.filtered = data.filter(item => item.active); this.count = this.filtered.length; this.timestamp = Date.now(); this.loading = false; } // ✅ 拆分为多个小 action @action handleComplexOperation(data) { this.setLoading(true); this.setData(data); this.processData(data); this.setLoading(false); } @action setLoading(loading) { this.loading = loading; } @action setData(data) { this.data = data; } @action processData(data) { this.filtered = data.filter(item => item.active); this.count = this.filtered.length; this.timestamp = Date.now(); }

常见错误

1. 在异步回调中直接修改状态

javascript
// ❌ 错误 @action async fetchData() { const data = await fetch('/api/data'); this.data = await data.json(); // 不在 action 中 } // ✅ 正确 @action async fetchData() { const data = await fetch('/api/data'); runInAction(() => { this.data = data.json(); }); }

2. 忘记使用 action.bound

javascript
// ❌ 错误:this 可能丢失 class Component { @action handleClick() { this.count++; } render() { return <button onClick={this.handleClick}>Click</button>; } } // ✅ 正确:使用 action.bound class Component { @action.bound handleClick() { this.count++; } render() { return <button onClick={this.handleClick}>Click</button>; } }

性能优化

  1. 使用 action 批量更新:减少 reaction 触发次数
  2. 避免在循环中创建 action:复用 action 函数
  3. 合理使用 runInAction:只在必要时使用
  4. 使用 action.bound:避免重复 bind

总结

  • action 是修改 observable 状态的唯一推荐方式
  • 使用 action 可以批量更新、提高性能、便于调试
  • 优先使用 action.bound 处理事件处理器
  • 异步操作中使用 runInAction 修改状态
  • 合理拆分复杂的 action,提高可维护性
标签:Mobx