observable 对象

用法

  • observable(value)
  • @observable classProperty = value

Observable 值可以是JS基本数据类型、引用类型、普通对象、类实例、数组和映射。 匹配类型应用了以下转换规则,但可以通过使用调节器进行微调。请参见下文。

  1. 如果 value 是ES6的 Map : 会返回一个新的 Observable Map。如果你不只关注某个特定entry的更改,而且对添加或删除其他entry时也做出反应的话,那么 Observable maps 会非常有用
  2. 如果 value 是数组,会返回一个 Observable Array
  3. 如果 value 是没有原型的对象,那么对象会被克隆并且所有的属性都会被转换成可观察的。参见 Observable Object
  4. 如果 value 是有原型的对象,JavaSript 原始数据类型或者函数,会返回一个 observable.box(value)。MobX 不会将一个有原型的对象自动转换成可观察的,因为这是它构造函数的职责。在构造函数中使用 extendObservable 或者在类定义中使用 @observable
  5. 如果 value 是有原型的对象,JavaSript 原始数据类型或者函数,observable 会抛出。如果想要为这样的值创建一个独立的可观察引用,请使用 observable.box(value)代替。MobX 不会将一个有原型的对象自动转换成可观察的,因为这是它构造函数的职责。在构造函数中使用 extendObservable或在类定义上使用 @observable / decorate

乍看之下,这些规则可能看上去很复杂,但实际上实践当中你会发现他们是非常直观的。

  1. const map = observable.map({ key: "value"});
  2. map.set("key", "new value");
  3. const list = observable([1, 2, 4]);
  4. list[2] = 3;
  5. const person = observable({
  6. firstName: "Clive Staples",
  7. lastName: "Lewis"
  8. });
  9. person.firstName = "C.S.";
  10. const temperature = observable.box(20);
  11. temperature.set(25);

api

observable.object(props, decorators?, options?) 或 observable({})

创建一个可被监听的对象
注意,属性映射中的任意 getters 都会转化成计算属性。

observable.array(values?) 或 observable([]) 创建一个可被监听的数组

  1. observable.array(values, { deep: false })
  2. observable.array(values, { name: "my array" })


除了所有内置函数,observable 数组还可以使用下面的好东西:

  • intercept(interceptor) - 可以用来在任何变化作用于数组前将其拦截。参见 observe & intercept
  • observe(listener, fireImmediately? = false) - 监听数组的变化。回调函数将接收表示数组拼接或数组更改的参数,它符合 ES7 提议。它返回一个清理函数以用来停止监听器。
  • clear() - 从数组中删除所有项。
  • replace(newItems) - 用新项替换数组中所有已存在的项。
  • find(predicate: (item, index, array) => boolean, thisArg?) - 基本上等同于 ES7 的 Array.find提议。
  • findIndex(predicate: (item, index, array) => boolean, thisArg?) - 基本上等同于 ES7 的 Array.findIndex 提议。
  • remove(value) - 通过值从数组中移除一个单个的项。如果项被找到并移除的话,返回 true
  • [MobX 4 及以下版本] peek() - 和 slice() 类似, 返回一个有所有值的数组并且数组可以放心的传递给其它库。

不同于 sortreverse 函数的内置实现,observableArray.sort 和 observableArray.reverse 不会改变数组本身,而只是返回一个排序过/反转过的拷贝。在 MobX 5 及以上版本中会出现警告。推荐使用 array.slice().sort() 来替代。

observable.map(values, options?) 或 observable(new Map()) 创建一个可被监听的map

  1. observable.map(values, { deep: false });
  2. observable.map(values, { name: "my array" });

下列 observable 映射所暴露的方法是依据 ES6 Map 规范:

  • has(key) - 返回映射是否有提供键对应的项。注意键的存在本身就是可观察的。
  • set(key, value) - 把给定键的值设置为 value 。提供的键如果在映射中不存在的话,那么它会被添加到映射之中。
  • delete(key) - 把给定键和它的值从映射中删除。
  • get(key) - 返回给定键的值(或 undefined)。
  • keys() - 返回映射中存在的所有键的迭代器。插入顺序会被保留。
  • values() - 返回映射中存在的所有值的迭代器。插入顺序会被保留。
  • entries() - 返回一个(保留插入顺序)的数组的迭代器,映射中的每个键值对都会对应数组中的一项 [key, value]
  • forEach(callback:(value, key, map) => void, thisArg?) - 为映射中每个键值对调用给定的回调函数。
  • clear() - 移除映射中的所有项。
  • size - 返回映射中项的数量。

以下函数不属于 ES6 规范,而是由 MobX 提供:

  • toJS() - 将 observable 映射转换成普通映射。
  • toJSON(). 返回此映射的浅式普通对象表示。(想要深拷贝,请使用 mobx.toJS(map))。
  • intercept(interceptor) - 可以用来在任何变化作用于映射前将其拦截。参见 observe & intercept
  • observe(listener, fireImmediately?) - 注册侦听器,在映射中的每个更改时触发,类似于为 Object.observe 发出的事件。想了解更多详情,请参见 observe & intercept
  • merge(values) - 把提供对象的所有项拷贝到映射中。values 可以是普通对象、entries 数组或者 ES6 字符串键的映射。
  • replace(values) - 用提供值替换映射全部内容。是 .clear().merge(values) 的简写形式。

    observable.box(value)

    observable.box(value) 接收任何值并把值存储到箱子中。 使用 .get() 可以获取当前值,使用 .set(newValue) 可以更新值。
    此外,还可以使用它的 .observe 方法注册回调,以监听对存储值的更改。 但因为 MobX 自动追踪了箱子的变化,在绝大多数情况下最好还是使用像 mobx.autorun 这样的 reaction 来替代。
    observable.box(scalar) 返回的对象签名是:

  • .get() - 返回当前值。

  • .set(value) - 替换当前存储的值并通知所有观察者。
  • intercept(interceptor) - 可以用来在任何变化应用前将其拦截。参见 observe & intercept
  • .observe(callback: (change) => void, fireImmediately = false): disposerFunction - 注册一个观察者函数,每次存储值被替换时触发。返回一个函数以取消观察者。参见 observe & interceptchange参数是一个对象,其中包含 observable 的 newValueoldValue
  1. observable.box(value, { deep: false }); // 表示任何将来的值都不会自动转成observable
  2. observable.box(value, { name: "my array" }); // 设置一个名字,用于调试定位什么的很方便
  3. import {observable} from "mobx";
  4. const cityName = observable.box("Vienna");
  5. console.log(cityName.get());
  6. // 输出 'Vienna'
  7. cityName.observe(function(change) {
  8. console.log(change.oldValue, "->", change.newValue);
  9. });
  10. cityName.set("Amsterdam");
  11. // 输出 'Vienna -> Amsterdam'

extendObservable(target, properties, decorators?, options?)

ExtendObservable 用来向已存在的目标对象添加 observable 属性。 属性映射中的所有键值对都会导致目标上的新的 observable 属性被初始化为给定值。 属性映射中的任意 getters 都会转化成计算属性。
decorators 参数用来重载用于指定属性的装饰器,类似于 decorateobservable.object
使用 deep: false 选项可使得新的属性变成浅的。也就是说,阻止它们的值自动转换成 observables 。

  1. var Person = function(firstName, lastName) {
  2. // 在一个新实例上初始化 observable 属性
  3. extendObservable(this, {
  4. firstName: firstName,
  5. lastName: lastName,
  6. get fullName() {
  7. return this.firstName + " " + this.lastName
  8. },
  9. setFirstName(firstName) {
  10. this.firstName = firstName
  11. }
  12. }, {
  13. setFirstName: action
  14. });
  15. }
  16. var matthew = new Person("Matthew", "Henry");
  17. // 向 observable 对象添加 observable 属性
  18. extendObservable(matthew, {
  19. age: 353
  20. });
  21. Copy

注意: observable.object(object) 实际上是 extendObservable({}, object) 的别名。
注意: 类似于 extendObservabledecorate 用来为对象引入 observable 属性。不同之处在于 extendObservable 被设计为直接在目标实例上引入属性,其中 decorate 将它们引入原型; 可以直接将它传递给构造函数 (类),也可以将其作为其他人的原型。
注意: 不能使用 extendObservable 来为 observable 数组或对象上引入新的属性。