Intercept & Observe

observeintercept 可以用来监测单个 observable(它们追踪嵌套的 observable) 的变化。
intercept 可以在变化作用于 observable 之前监测和修改变化。
observe 允许你在 observable 变化之后拦截改变。

Intercept

用法: intercept(target, propertyName?, interceptor)

  • target: 监测的 observable
  • propertyName: 可选参数,用来指定某个属性进行拦截。注意,intercept(user.name, interceptor)intercept(user, "name", interceptor) 根本是完全不同的。前者尝试给 user.name(或许根本不是一个 observable) 里面的当前值添加一个拦截器,而后者拦截 username 属性的变化。
  • interceptor: 在每次变化作用于 observable 后调用的回调函数。接收一个用来描述变化的对象。

intercept 应该告诉 MobX 对于当前变化需要做些什么。
因此,它应该做下列事情中的某个:

  1. 把从函数中接收到的 change 对象原样返回,这样变化会被应用。
  2. 修改 change 对象并将其返回,例如数据标准化。但不是所有字段都是可以修改的,参见下面。
  3. 返回 null,这表示此次变化可以被忽略而且不会应用。这是一个强大的概念,例如可以使你的对象临时性的不可改变。
  4. 抛出异常,例如如果一些不变量未被满足。

该函数返回一个 disposer 函数,当调用时可以取消拦截器。
可以为同一个 observable 注册多个拦截器。
它们会按照注册的顺序串联起来。
如果一个拦截器返回 null 或抛出异常,其它的拦截器不会再执行。
还可以注册一个拦截器同时作用于父对象和某个属性。
在这种情况下,父对象的拦截器在属性拦截器之前运行。

  1. const theme = observable({
  2. backgroundColor: "#ffffff"
  3. })
  4. const disposer = intercept(theme, "backgroundColor", change => {
  5. if (!change.newValue) {
  6. // 忽略取消设置背景颜色
  7. return null;
  8. }
  9. if (change.newValue.length === 6) {
  10. // 补全缺少的 '#' 前缀
  11. change.newValue = '#' + change.newValue;
  12. return change;
  13. }
  14. if (change.newValue.length === 7) {
  15. // 这一定是格式正确的颜色代码!
  16. return change;
  17. }
  18. if (change.newValue.length > 10) disposer(); // 不再拦截今后的任何变化
  19. throw new Error("This doesn't like a color at all: " + change.newValue);
  20. })

Observe

用法: observe(target, propertyName?, listener, invokeImmediately?)

  • target: 观察的 observable
  • propertyName: 可选参数,用来指定某个属性进行观察。注意,observe(user.name, listener)observe(user, "name", listener) 根本是完全不同的。前者观察 user.name(或许根本不是一个 observable) 里面的当前值,而后者观察 username 属性。
  • listener: 在每次变化作用于 observable 后调用的回调函数。接收一个用来描述变化的对象,除了装箱的 observable,它调用 listener 有两个参数: newValue、oldValue
  • invokeImmediately: 默认是 false。如果你想 observe 直接使用 observable 的状态(而不是等待第一次变化)调用 listener 的话,把它设置为 true。不是所有类型的 observable 都支持。

该函数返回一个 disposer 函数,当调用时可以取消观察者。
注意,transaction 不影响 observe 方法工作。
意味着即使在一个 transaction 中,observe 也会触发每个变化的监听器。
因此,autorun 通常是一个更强大的和更具声明性的 observe 替代品。

observe 会响应对应的变动,而像是 autorunreaction 则会对新值做出响应。大多数情况下,后者足够用了。

示例:

  1. import {observable, observe} from 'mobx';
  2. const person = observable({
  3. firstName: "Maarten",
  4. lastName: "Luther"
  5. });
  6. const disposer = observe(person, (change) => {
  7. console.log(change.type, change.name, "from", change.oldValue, "to", change.object[change.name]);
  8. });
  9. person.firstName = "Martin";
  10. // 输出: 'update firstName from Maarten to Martin'
  11. disposer();
  12. // 忽略任何未来的变化
  13. // 观察单个字段
  14. const disposer2 = observe(person, "lastName", (change) => {
  15. console.log("LastName changed to ", change.newValue);
  16. });

相关博客: @mweststrate/object-observe-is-dead-long-live-mobservable-observe-ad96930140c5">Object.observe 已死。mobx.observe 永生

事件概览

interceptobserve 的回调函数接收一个事件对象,它至少有如下属性:

  • object: 触发事件的 observable
  • type: 当前事件类型(字符串)

对于每种类型可用的附加字段:

observable 类型 事件类型 属性 描述 intercept 期间能否获得 能否被 intercept 修改
对象 add name 添加的属性名称
newValue 分配的新值
update* name 更新的属性名称
newValue 分配的新值
oldValue 被替换的值
数组 splice index splice 的起始索引。 pushunshiftreplace 等方法可以触发 splice。
removedCount 删除项的数量
added 添加到数组中的项
removed 数组中移除的项
addedCount 添加项的数量
update index 更新的单个项的索引
newValue (将)分配的新值
oldValue 被替换的值
映射 add name 添加项的名称
newValue 分配的新值
update name 更新项的名称
newValue 分配的新值
oldValue 被替换的值
delete name 删除项的名称
oldValue 删除项的值
Boxed & computed observables create newValue 创建期间分配的新值。只有 boxed observables 的 spy 事件可获得
update newValue 分配的新值
oldValue observable 的前一个值

* 注意,对象的 update 事件不会为更新的计算值(因为它们没有变化)触发。但是可以通过使用 observe(object, 'computedPropertyName', listener) 明确地订阅特定属性来观察它们。