mobx 学习:core - 可观察状态(Observable state)

对 makeObservable/makeAutoObservable/observable 几个 api 的学习
更新于: 2021-12-19 12:57:29

属性,完整的对象,数组,Maps 和 Sets 都可以被转化为可观察对象。 使得对象可观察的基本方法是使用 makeObservable 为每个属性指定一个注解

makeObservable

这个函数可以捕获已经存在的对象属性并且使得它们可观察

makeObservable(target, annotations?, options?)

常用的注解如下

  • observable 定义一个存储 state 的可追踪字段。
  • action 将一个方法标记为可以修改 state 的 action。
  • computed 标记一个可以由 state 派生出新的值并且缓存其输出的 getter。

使用示例

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

class Doubler {
  value;

  constructor(value) {
    makeObservable(this, {
      value: observable,
      double: computed,
      increment: action,
      fetch: flow,
    });
    this.value = value;
  }

  get double() {
    return this.value * 2;
  }

  increment() {
    this.value++;
  }

  *fetch() {
    const response = yield fetch('/api/value');
    this.value = response.json();
  }
}

makeAutoObservable

makeAutoObservable 就像是加强版的 makeObservable,在默认情况下它将推断所有的属性。你仍然可以使用 overrides 重写某些注解的默认行为。

推断规则:

  • 所有 自有 属性都成为 observable
  • 所有 getters 都成为 computed
  • 所有 setters 都成为 action
  • 所有 prototype 中的 functions 都成为 autoAction
  • 所有 prototype 中的 generator functions 都成为 flow。(需要注意,generators 函数在某些编译器配置中无法被检测到,如果 flow 没有正常运行,请务必明确地指定 flow 注解。)
  • overrides 参数中标记为 false 的成员将不会被添加注解。例如,将其用于像标识符这样的只读字段。

observable

observable 注解可以作为一个函数进行调用,从而一次性将整个对象变成可观察的source 对象将会被克隆并且所有的成员都将会成为可观察的,类似于 makeAutoObservable 做的那样。 同样,你可以传入一个 overrides 对象来为特定的成员提供特定的注解。

import { observable, autorun, configure } from "mobx";

// 去掉修改 store 时的 warning 提示
configure({ enforceActions: "never", });

const todos = observable([
  { title: "Spoil tea", completed: true },
  { title: "Make coffee", completed: false },
]);

autorun(() => {
  console.log(
    "Remaining:",
    todos
      .filter((todo) => !todo.completed)
      .map((todo) => todo.title)
      .join(", ")
  );
});
// 打印: 'Remaining: Make coffee'

todos[0].completed = false;
// 打印: 'Remaining: Spoil tea, Make coffee'

todos[2] = { title: "Take a nap", completed: false };
// 打印: 'Remaining: Spoil tea, Make coffee, Take a nap'

todos.shift();
// 打印: 'Remaining: Make coffee, Take a nap'

setTimeout(() => {
    todos[1].completed = true;
}, 1000);

处理深层对象

import { observable, autorun, configure } from "mobx";

configure({ enforceActions: "never" });

const todos = observable(
  [
    {
      title: "Spoil tea",
      completed: true,
      someDeepObj: {
        level1: {
          level2: {
            level3: "value3",
          },
        },
      },
    },
    { title: "Make coffee", completed: false },
  ],
);

autorun(() => {
  console.log(
    "Remaining:",
    todos
  );
});
// 打印: 'Remaining: Make coffee'

setTimeout(() => {
  todos[0].someDeepObj.level1.level2.level3 = "abc";
}, 1000);