Reaction

用法: reaction(() => data, data => { sideEffect }, options?).

autorun 的变种,对于如何追踪 observable 赋予了更细粒度的控制。 它接收两个函数参数,第一个(数据 函数)是用来追踪并返回数据作为第二个函数(效果 函数)的输入。 不同于 autorun 的是当创建时副作用不会直接运行,只有在数据表达式首次返回一个新值后才会运行。 在执行副作用时访问的任何 observable 都不会被追踪。

副作用是可以去抖的,就像 autorunAsyncreaction 返回一个清理函数。 传入 reaction 的函数当调用时会接收一个参数,即当前的 reaction,可以用来在执行期间进行清理。

值得注意的是副作用对数据函数中访问的数据作出反应,这可能会比实际在效果函数使用的数据要少。 此外,副作用只会在表达式返回的数据发生更改时触发。 换句话说: reaction 需要你生产副作用中所需要的东西。

选项

Reaction 接收第三个参数,它是一个参数对象,有如下可选的参数:

  • context: 传给 reaction 的函数所使用的 this。默认是 undefined(使用箭头函数代替!)。
  • fireImmediately: 布尔值,用来标识效果函数是否在数据函数第一次运行后立即触发。默认值是 false,如果一个布尔值作为传给 reaction 的第三个参数,那么它会被解释为 fireImmediately 选项。
  • delay: 可用于对效果函数进行去抖动的数字(以毫秒为单位)。如果是 0(默认值) 的话,那么不会进行去抖。
  • compareStructural: 默认值是 false。如果是 true 的话,数据 函数的返回值会在结构上与前一个返回值进行比较,并且效果函数只有在输出结构改变时才会被调用。
  • name: 字符串,用于在例如像 spy 这样事件中用作此 reaction 的名称。

示例

在下面的示例中,reaction1reaction2autorun1 都会对 todos 数组中的 todo 的添加、删除或替换作出反应。 但只有 reaction2autorun 会对某个 todo 的 title 变化作出反应,因为在 reaction2 的数据表达式中使用了 title,而 reaction1 的数据表达式没有使用。 autorun 追踪完整的副作用,因此它将始终正确触发,但也更容易意外地访问相关数据。 还可参见 MobX 会对什么作出反应?.

  1. const todos = observable([
  2. {
  3. title: "Make coffee",
  4. done: true,
  5. },
  6. {
  7. title: "Find biscuit",
  8. done: false
  9. }
  10. ]);
  11. // reaction 的错误用法: 对 length 的变化作出反应, 而不是 title 的变化!
  12. const reaction1 = reaction(
  13. () => todos.length,
  14. length => console.log("reaction 1:", todos.map(todo => todo.title).join(", "))
  15. );
  16. // reaction 的正确用法: 对 length 和 title 的变化作出反应
  17. const reaction2 = reaction(
  18. () => todos.map(todo => todo.title),
  19. titles => console.log("reaction 2:", titles.join(", "))
  20. );
  21. // autorun 对它函数中使用的任何东西作出反应
  22. const autorun1 = autorun(
  23. () => console.log("autorun 1:", todos.map(todo => todo.title).join(", "))
  24. );
  25. todos.push({ title: "explain reactions", done: false });
  26. // 输出:
  27. // reaction 1: Make coffee, find biscuit, explain reactions
  28. // reaction 2: Make coffee, find biscuit, explain reactions
  29. // autorun 1: Make coffee, find biscuit, explain reactions
  30. todos[0].title = "Make tea"
  31. // 输出:
  32. // reaction 2: Make tea, find biscuit, explain reactions
  33. // autorun 1: Make tea, find biscuit, explain reactions

粗略地讲,reaction 是 computed(expression).observe(action(sideEffect))autorun(() => action(sideEffect)(expression) 的语法糖。