observable 调节器

调节器可以作为装饰器或者组合 extendObservableobservable.object 使用,以改变特定属性的自动转换规则。

  • observable.deep: 任何 observable 都使用的默认的调节器。它把任何分配的、非原始数据类型的、非 observable 的值转换成 observable。
  • observable.ref: 禁用自动的 observable 转换,只是创建一个 observable 引用。
  • observable.shallow: 只能与集合组合使用。 将任何分配的集合转换为浅 observable (而不是深 observable)的集合。 换一种说法; 集合中的值将不会自动变为 observable。
  • computed: 创建一个衍生属性, 参见 computed
  • action: 创建一个动作, 参见 action

深层可观察性

当 MobX 创建一个 observable 对象时,(使用 observableobservable.objectextendObservable),它引入的 observable 属性默认是使用 deep 调节器的。deep 调节器主要是为任何新分配的值递归调用 observable(newValue)。会依次使用 deep 调节器…你可以想象。

这是一个非常便利的默认设置。无需额外的工作,分配给 observable 的所有值本身也将转变成 observable(除非它们已经是),因此不需要额外的工作就可使对象转变成深 observable 。

引用可观察性

然后在某些情况下,不需要将对象转变成 observable 。典型案例就是不可变对象,或者不是由你管理,而是由外部库管理的对象。例如 JSX 元素、DOM 元素、像 History、window 这样的原生对象,等等。对于这类对象,只需要存储引用而不用把它们转变成 observable 。

对于这些情况,可以使用 ref 调节器。它会确保创建 observable 属性时,只追踪引用而不会把它的值转变成 observable 。示例:

  1. class Message {
  2. @observable message = "Hello world"
  3. // 虚构的例子,如果 author 是不可变的,我们只需要存储一个引用,不应该把它变成一个可变的 observable 对象
  4. @observable.ref author = null
  5. }

或者使用 ES5 语法:

  1. function Message() {
  2. extendObservable({
  3. message: "Hello world",
  4. author: observable.ref(null)
  5. })
  6. }

注意,可以通过使用 const box = observable.shallowBox(value) 来创建一个装箱的 observable 引用

浅层可观察性

observable.shallow 调节器会应用“单层”可观察性。如果想创建一个 observable 引用的集合,那你会需要它。如果新集合分配给具有此调节器的属性,那么它会转变成 observable,但它的值将保持原样,不同于 deep 的是它不会递归。示例:

  1. class AuthorStore {
  2. @observable.shallow authors = []
  3. }

在上面的示例中,使用普通的 author 数组分配给 authors 的话,会使用 observables 数组来更新 author,observables 数组包含原始的、非 observable 的 author 。

注意这些方法可用于手动创建浅集合: observable.shallowObjectobservable.shallowArrayobservable.shallowMapextendShallowObservable

Action & Computed

actionaction.boundcomputedcomputed.struct 同样可以作为调节器使用。参见 computedaction

  1. const taskStore = observable({
  2. tasks: observable.shallow([]),
  3. taskCount: computed(function() {
  4. return this.tasks.length
  5. }),
  6. clearTasks: action.bound(function() {
  7. this.tasks.clear()
  8. })
  9. })

asStructure

MobX 2 中有 asStructure 调节器,它在实践中极少被使用,或者只能在使用 reference / shallow 更适合(例如使用不可变数据)的情况下使用。计算属性和 reaction 的结构比较仍是可能的。

调节器的效果

  1. class Store {
  2. @observable/*.deep*/ collection1 = []
  3. @observable.ref collection2 = []
  4. @observable.shallow collection3 = []
  5. }
  6. const todos = [{ test: "value" }]
  7. const store = new Store()
  8. store.collection1 = todos;
  9. store.collection2 = todos;
  10. store.collection3 = todos;

完成这些分配后:

  1. collection1 === todos 是 false; todos 的内容会被克隆至一个新的 observable 数组。
  2. collection1[0] === todos[0] 是 false; 第一个 todo 是个普通对象,因此它被克隆至一个存储在数组中的 observable 对象。
  3. collection2 === todos 是 true; todos 保持不变, 而且是非 observable。 只有 collection2 属性本身是 observable 。
  4. collection2[0] === todos[0] 是 true; 理由同 3。
  5. collection3 === todos 是 false; collection3 是一个新的 observable 数组。
  6. collection3[0] === todos[0] 是 true; collection3 的值只是浅的转变成 observable,但数组的内容保持不变。