创建 observable 数据结构和 reactions(反应)

Atoms

在某些时候,你可能想要有更多的数据结构或其他可以在响应式计算中使用的东西(如流)。
要实现这个其实非常容易,使用 Atom 类即可。
Atom 可以用来通知 Mobx 某些 observable 数据源被观察或发生了改变。
当数据源被使用或不再使用时,MobX 会通知 atom 。

下面的示例演示了如何创建一个 observable Clock,它可以用在响应式函数中,并且返回当前时间。
这个 clock 只有当它被观察了才会运行。

此示例演示了 Atom 类的完整API。

  1. import {Atom, autorun} from "mobx";
  2. class Clock {
  3. atom;
  4. intervalHandler = null;
  5. currentDateTime;
  6. constructor() {
  7. // 创建一个 atom 用来和 MobX 核心算法交互
  8. this.atom = new Atom(
  9. // 第一个参数: atom 的名字,用于调试
  10. "Clock",
  11. // 第二个参数(可选的): 当 atom 从未被观察到被观察时的回调函数
  12. () => this.startTicking(),
  13. // 第三个参数(可选的): 当 atom 从被观察到不再被观察时的回调函数
  14. // 注意同一个 atom 在这两个状态之间转换多次
  15. () => this.stopTicking()
  16. );
  17. }
  18. getTime() {
  19. // 让 MobX 知道这个 observable 数据源已经使用了
  20. // 如果 atom 当前是被某些 reaction 观察的,那么 reportObserved 方法会返回 true
  21. // 如果需要的话,reportObserved 还会触发 onBecomeObserved 事件处理方法(startTicking)
  22. if (this.atom.reportObserved()) {
  23. return this.currentDateTime;
  24. } else {
  25. // 显然 getTime 被调用的同时并没有 reaction 正在运行
  26. // 所以,没有人依赖这个值,因此 onBecomeObserved 处理方法(startTicking)不会被触发
  27. // 根据 atom 的性质,在这种情况下它可能会有不同的表现(像抛出错误、返回默认值等等)
  28. return new Date();
  29. }
  30. }
  31. tick() {
  32. this.currentDateTime = new Date();
  33. // 让 MobX 知道这个数据源发生了改变
  34. this.atom.reportChanged();
  35. }
  36. startTicking() {
  37. this.tick(); // 最初的运行
  38. this.intervalHandler = setInterval(
  39. () => this.tick(),
  40. 1000
  41. );
  42. }
  43. stopTicking() {
  44. clearInterval(this.intervalHandler);
  45. this.intervalHandler = null;
  46. }
  47. }
  48. const clock = new Clock();
  49. const disposer = autorun(() => console.log(clock.getTime()));
  50. // ... 输出每一秒的时间
  51. disposer();
  52. // 停止输出。如果没有人使用同一个 `clock` 的话,clock 也将停止运行。

Reactions(反应)

Reaction 允许你创建你自己的 自动运行器
当函数应该再次执行时, Reaction 会追踪函数和信号,因为一个或多个依赖关系已更改。

这是 autorun 如何使用 Reaction 来定义的:

  1. export function autorun(view: Lambda, scope?: any) {
  2. if (scope)
  3. view = view.bind(scope);
  4. const reaction = new Reaction(view.name || "Autorun", function () {
  5. this.track(view);
  6. });
  7. // 运行刚刚创建的 reaction 或将其列入计划表中
  8. if (isComputingDerivation() || globalState.inTransaction > 0)
  9. globalState.pendingReactions.push(reaction);
  10. else
  11. reaction.runReaction();
  12. return reaction.getDisposer();
  13. }