• Reaction
    • 选项
    • 示例

    Reaction

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

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

    reaction 返回一个清理函数。

    传入 reaction 的第二个函数(副作用函数)当调用时会接收两个参数。第一个参数是由 data 函数返回的值。第二个参数是当前的 reaction,可以用来在执行期间清理 reaction

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

    选项

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

    • fireImmediately: 布尔值,用来标识效果函数是否在数据函数第一次运行后立即触发。默认值是 false
    • delay: 可用于对效果函数进行去抖动的数字(以毫秒为单位)。如果是 0(默认值) 的话,那么不会进行去抖。
    • equals: 默认值是 comparer.default 。如果指定的话,这个比较器函数被用来比较由 数据 函数产生的前一个值和后一个值。只有比较器函数返回 false 效果 函数才会被调用。此选项如果指定的话,会覆盖 compareStructural 选项。
    • name: 字符串,用于在例如像 spy 这样事件中用作此 reaction 的名称。
    • onError: 用来处理 reaction 的错误,而不是传播它们。
    • scheduler: 设置自定义调度器以决定如何调度 autorun 函数的重新运行

    示例

    在下面的示例中,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

    在下面的示例中,reaction3 会对 counter 中的 count 作出反应。当调用 reaction 时,第二个参数会作为清理函数使用。下面的示例展示了 reaction 只会调用一次。

    1. const counter = observable({ count: 0 });
    2. // 只调用一次并清理掉 reaction : 对 observable 值作出反应。
    3. const reaction3 = reaction(
    4. () => counter.count,
    5. (count, reaction) => {
    6. console.log("reaction 3: invoked. counter.count = " + count);
    7. reaction.dispose();
    8. }
    9. );
    10. counter.count = 1;
    11. // 输出:
    12. // reaction 3: invoked. counter.count = 1
    13. counter.count = 2;
    14. // 输出:
    15. // (There are no logging, because of reaction disposed. But, counter continue reaction)
    16. console.log(counter.count);
    17. // 输出:
    18. // 2

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