我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

根据官方描述,MobX是一种简单、可扩展并且身经百战的状态管理解决方案。它对标的是redux。所以,官方描述中,也处处在针对redux暗中做对比。“许多状态管理解决方案会——比如通过使状态不可变——试图限制你修改状态的方式。但这样就会引出新的问题:数据需要被归一化、引用的完整性无法得到保证。”

苏南大叔:mobx状态管理解决方案对标redux,mobx新手入门篇 - mobx新手入门
mobx状态管理解决方案对标redux,mobx新手入门篇(图4-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0mobx@6.13.5。本文只是在苏南大叔的视角来观察mobxmobxredux一样,都可以独立使用。本文代码基于官方教程代码,略有修改。

官方入门教程

这个mobx官方有个教程,号称“十分钟”就可以搞定mobx。苏南大叔反正是反复看了好多个十分钟,还是云里雾里。

苏南大叔:mobx状态管理解决方案对标redux,mobx新手入门篇 - mobx-offical
mobx状态管理解决方案对标redux,mobx新手入门篇(图4-2)

苏南大叔就分为两部分讲述对这个教程的理解。一个是普通的todolist的需求写法,第二个是使用mobx如何实现这个todolist需求写法。至于mobxreact相结合的事情,到下一篇文章里面讲述。

加载mobx

根据不同的使用情况,可以选择不同的加载方式。

浏览器加载

可以选择别的地址加载mobx,不过记得加载umd版本的mobx.js

<script src="https://cdnjs.cloudflare.com/ajax/libs/mobx/6.13.5/mobx.umd.production.min.js"></script>
<script>
const { makeObservable, observable, computed, action, autorun } = mobx;
</script>

纯node加载

node环境下加载的话,先安装再引入即可。

npm i mobx --save
const { makeObservable, observable, computed, action, autorun } = require("mobx");
import mbox, { makeObservable, observable, computed, action, autorun } from 'mobx';

需求说明

这个todoList的类,需求就是个task管理器。

  • 一个task有两个属性,分别是task(名字)、completed(是否完成)。
  • task管理器的.completedTodosCount属性,就是统计一下有多少task是被完成的。
  • task管理器的report()属性,是用于整体统计的。包括:下一个未完成的任务、任务进度:任务完成数/任务总数。

mobx版todolist(响应式)

这个响应式的mbox版本的todolist,该如何编写代码呢?

const { makeObservable, observable, computed, action, autorun } = require("mobx");
class ObservableTodoStore {
  todos = [];
  constructor() {
    makeObservable(this, {
      todos: observable,
      completedTodosCount: computed,
      report: computed,
      addTodo: action,
      modifyTodo: action,
    });
    autorun(() => console.log(this.report));
  }
  get completedTodosCount() {
    return this.todos.filter((todo) => todo.completed === true).length;
  }
  get report() {
    if (this.todos.length === 0) return "";
    const nextTodo = this.todos.find((todo) => todo.completed === false);
    const percent = `进度:${this.completedTodosCount}/${this.todos.length}`;
    return percent + `,准备:${nextTodo ? nextTodo.task : "<无>"}`;
  }
  modifyTodo(id, obj) {
    this.todos[id] = {
      ...this.todos[id],
      ...obj,
    };
  }
  addTodo(task) {
    this.todos.push({
      task: task,
      completed: false,
      assignee: "sunan",
    });
  }
}
const todoStore = new ObservableTodoStore();
todoStore.addTodo("阅读 MobX 教程");
todoStore.addTodo("试用 MobX");
todoStore.modifyTodo(0, { completed: true });
todoStore.modifyTodo(1, { task: "在自己的项目中试用 MobX" });
todoStore.modifyTodo(0, { task: "理解 MobX 教程" });

运行结果:

进度:0/1,准备:阅读 MobX 教程
进度:0/2,准备:阅读 MobX 教程
进度:1/2,准备:试用 MobX
进度:1/2,准备:在自己的项目中试用 MobX

苏南大叔:mobx状态管理解决方案对标redux,mobx新手入门篇 - mobx代码,没有report
mobx状态管理解决方案对标redux,mobx新手入门篇(图4-3)

普通版todolist(对照组)

下面的代码,在浏览器里面能用,在纯node环境下,也能用。它就是一个普通的类,没有涉及到mobx

class TodoStore {
  todos = [];
  get completedTodosCount() {
    return this.todos.filter((todo) => todo.completed === true).length;
  }
  get report() {
    if (this.todos.length === 0) return "";
    const nextTodo = this.todos.find((todo) => todo.completed === false);
    const percent = `进度:${this.completedTodosCount}/${this.todos.length}`;
    return percent + `,准备:${nextTodo ? nextTodo.task : "<无>"}`;
  }
  addTodo(task) {
    this.todos.push({
      task: task,
      completed: false,
    });
  }
}
const todoStore = new TodoStore();
todoStore.addTodo("<0>阅读 MobX 教程"); // 添加新任务
console.log(todoStore.report); // 任务进度汇报
todoStore.addTodo("<1>试用 MobX");
console.log(todoStore.report);
todoStore.todos[0].completed = true; // 完成第一个进度(目前正式的`mobx`,并不推荐这么写)
console.log(todoStore.report); // 任务进度汇报
todoStore.todos[1].task = "<1>在自己的项目中试用 MobX"; // 修改未完成任务(第二个任务)的名称
console.log(todoStore.report);
todoStore.todos[0].task = "<0>理解 MobX 教程"; // 修改已完成任务(第一个任务)的名称,意义不大...
console.log(todoStore.report);

输出:

进度:0/1,准备:<0>阅读 MobX 教程
进度:0/2,准备:<0>阅读 MobX 教程
进度:1/2,准备:<1>试用 MobX
进度:1/2,准备:<1>在自己的项目中试用 MobX
进度:1/2,准备:<1>在自己的项目中试用 MobX

苏南大叔:mobx状态管理解决方案对标redux,mobx新手入门篇 - 普通代码,多条report
mobx状态管理解决方案对标redux,mobx新手入门篇(图4-4)

代码对比

两者最明显的区别是:普通代码的版本,需要【多次调用】.report。而mbox版本的,是通过autorun()执行的,并没有明显的调用执行。

在任务调度一致的前提下,两者的输出是略有不同的。

  • mobx版本下,输出为5条。顶部多一个"",尾部少一个输出。(所以,这里存在着怀疑)
  • 普通版本下,输出5条。

官方的说法是:“因为 report实际上并没有因为第五行代码的重命名而发生改变,尽管它背后的数据变了。另一方面,更改第一个待办的名称确实更新了report,因为report正使用着那个新名字。这很好地证明了autorun不仅监视观察着todos数组,还监视着待办条目中的各个属性。”

代码编写方面,最显著的就是在类的构造器上,增加了下面的代码:

constructor() {
    makeObservable(this, {
      todos: observable,                // 维护的状态
      completedTodosCount: computed,    // 属性值,带get开头的
      report: computed,
      addTodo: action,                  // 修改状态的函数
      modifyTodo: action,
    });
    autorun(() => console.log(this.report)); // 自动执行,被观察的变量变化的话,它就会被执行
}

结语

本文以建立mbox的初步印象为主要目的,mobx的技术细节,后续再进行深入讨论。

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   mobx