mobx 学习:Mobx思想

The gist of MobX · MobX
更新于: 2022-08-16 00:47:59

三个概念

  1. State(状态)
  2. Actions(动作)
  3. Derivations(派生)

原则

mobx 单向数据流
mobx 单向数据流

Mobx 使用单向数据流,利用 action 改变 state ,进而更新所有受影响的 view

  1. 所有的 derivations 将在 state 改变时自动且原子化地更新。因此不可能观察中间值。
  2. 所有的 dervations 默认将会同步更新,这意味着 action 可以在 state 改变 之后安全的直接获得 computed 值。
  3. computed value 的更新是惰性的,任何 computed value 在需要他们的副作用发生之前都是不激活的。
  4. 所有的 computed value 都应是纯函数,他们不应该修改 state

State: 定义 State 并使其可观察

makeAutoObservable 可以简化操作,这个例子中为了演示

import { makeObservable, observable, action } from 'mobx';

class Todo {
  id = Math.random();
  title = '';
  finished = false;

  constructor(title) {
    makeObservable(this, {
      title: observable,
      finished: observable,
      toggle: action,
    });
    this.title = title;
  }

  toggle() {
    this.finished = !this.finished;
  }
}

使用 Action 更新 State

Action(动作) 是任意可以改变 State(状态) 的代码,比如用户事件处理、后端推送数据处理、调度器事件处理等等。

使用 Action 可以帮助您更好地组织代码,并防止您在无意中修改 State

在 MobX 术语中,可以修改 State 的方法被称为 action(动作) 。这与基于当前状态来生成新信息的 view(视图) 是不同的。 您代码中的每一个方法只应完成上述两个目标中的一个。

 

Derivations: Mobx 区分了两种 Derivation

Computed values,总是可以通过纯函数从当前的可观测 State 中派生。
Reactions, 当 State 改变时需要自动运行的副作用 (命令式编程和响应式编程之间的桥梁)

使用 Reaction 的原则

  • 当最开始使用MobX时,人们容易过度使用 Reaction。
  • 黄金法则是,如果要基于当前 State 创建值,请始终使用 computed。

通过 computed 对派生值进行建模

import { makeObservable, observable, computed } from 'mobx';

class TodoList {
  todos = [];
  get unfinishedTodoCount() {
    return this.todos.filter((todo) => !todo.finished).length;
  }
  constructor(todos) {
    makeObservable(this, {
      todos: observable,
      unfinishedTodoCount: computed,
    });
    this.todos = todos;
  }
}

常用的 Reaction

  • computed
  • observer
  • 特殊业务场景:可以使用 autorun ,reaction 或 when 方法来订制你的特殊业务场景
// 一个自动观察state的函数
autorun(() => {
    console.log("Tasks left: " + todos.unfinishedTodoCount)
})

Q&A

使用mobx时修改state可以不用action,为什么教程里强调要使用?(高赞回复其实是错的)

尽管如此,MobX 还是提供了 actions 这个可选的内置概念。 如果你现在就想要了解如何编写 actions,请阅读 Actions 章节。很简单! 使用 actions 是有优势的: 它们可以帮助你把代码组织的更好,还能在状态何时何地应该被修改这个问题上帮助你做出明智的决定。这是官网的说法,说是可选的,我的意思是我的state里有很多个像loadingState = fasle,isAnimationShow = false,selectElementIndex = 0, selectGroupIndex = 0 像这样的属性,如果要修改的话,不是得每一个都要写一个action?

其它回复:里面内置的transaction可以避免多个observable的修改导致不必要的多次渲染

 

必须要通过 action 去更新 Store?

原理上不必要,原则上必要。你直接mutable的方式直接更改Store也是能够触发响应式更新,但是mobx强烈不建议你这样做,因为你会丢失以下好处:
(1) 能够清晰表达出一个函数修改状态的意图,有利于项目维护
(2) action结合开发者工具,提供了非常有用的调试信息
当启用严格模式时,修改store状态需要强制使用action,参见全局配置enforceActions。MobX并不像redux那样,从原理上就限制了state的更新方式(防止玩花活儿,如: _.set(obj,'xx.x.y.x.z', ‘yourvalue’),只能靠这种约定的方式去限制。所以强烈建议开启此选项。

 

关于这个问题,个人测试结果

  1. 能够清晰表达出一个函数修改状态的意图,有利于项目维护
  2. action 结合开发者工具,提供了非常有用的调试信息
  3. 当启用严格模式时,修改 store 状态需要强制使用 action ,参见全局配置 enforceActions
  4. 里面内置的 transaction 可以避免多个 observable 的修改导致不必要的多次渲染 这个测试过了简单多种状态还是可以自动判断,只执行一次的,所以观点不完全对

参考