Mobx' asFlat',' asReference'没有按预期工作

时间:2017-11-28 11:02:25

标签: javascript ecmascript-6 mobx ecmascript-next

我们在其中一个项目中使用了Mobx,并且我发现代码中经常使用asFlatasReference。根据我的理解,asReference仅在引用发生更改时才触发更改,但在对象上的任何属性发生更改时不会触发更改。相反,Mobx将跟踪标记为observable的对象的所有属性(假设在对象创建期间存在这些属性)。但我在下面的代码中看不到两者之间的行为有任何变化。

同样,asFlat允许属性本身可观察但不允许其任何子节点。这意味着向标记为asFlat的数组添加新值不会触发更改,但更改数组的引用将会。但是,在下面的代码中,两个阵列的行为完全相同。为什么会这样?

此外,asReferenceasFlat之间有什么区别,因为两者看起来相似?

  const {observable, asFlat, asReference, reaction} = mobx;

  class Car {

    constructor() {
      reaction(() => this.colors, () => console.log('colors changed: ',this.colors));
      reaction(() => this.colorsAsFlat, () => console.log('colorsAsFlat changed: ',this.colorsAsFlat));
      reaction(() => this.config, () => console.log('config changed: ',this.config));
      reaction(() => this.configAsReference, () => console.log('configAsReference changed: ',this.configAsReference));
    }

    @observable colors = [];
    @observable colorsAsFlat = asFlat([]);
    @observable config = {model : '7 Series'};
    @observable configAsReference = asReference({model : '7 Series'});
  }

  const bmw = new Car();

  bmw.colors.push('Red');
  bmw.colors[1] = 'Gray';
  bmw.colors = ['Black'];
  bmw.colors.push('Blue');

  bmw.colorsAsFlat.push('Red');
  bmw.colorsAsFlat[1] = 'Gray';
  bmw.colorsAsFlat = ['Black'];
  bmw.colorsAsFlat.push('Blue');

  console.log("Initial Config: ", bmw.config);

  bmw.config.model = '5 Series';
  bmw.config.autopilot = 'true';
  bmw.config = { sunroof : 'true'};

  bmw.configAsReference.model = '5 Series';
  bmw.configAsReference.autopilot = 'true';
  bmw.configAsReference = { sunroof : 'true'};

reaction仅用于跟踪可观察对象的变化,并会在可变属性发生变化时记录该变量。 Here同样是一个小提琴。观察此代码的控制台输出。

以上代码提出的问题:

  1. 为什么bmw.colors.push('Red')bmw.colors[1] = 'Gray'没有触发变更(反应)?
  2. bmw.colors = ['Black']解除了反应,但为什么colors数组也包含了' Blue'在蓝色'蓝色'在' Black'
  3. 之后分配
  4. colorsAsFlat即使声明为colors,也会触发与asFlat相同的更改。所以它应该仅在bmw.colorsAsFlat = ['Black']触发参考更改(并且它会这样做),但它也出乎意料地包含了' Blue'颜色。为什么会这样?
  5. 为什么在bmw.config声明后分配这两个属性时,记录Initial Config: {autopilot: "true", model: "5 Series"}会打印console.log
  6. 为什么bmw.config.model = '5 Series'没有反应?创建可观察对象时出现的Aren对象属性是否存在变化?
  7. configAsReference的行为符合预期,仅在更改引用时触发更改;因为反应仅在bmw.configAsReference = { sunroof : 'true'}上触发,这是一个参考变化。

1 个答案:

答案 0 :(得分:0)

  1. 仅当数据函数的返回值更改时,才会触发反应。默认比较将实际上仅执行this.colors === this.colors,因此效果将无法运行。尝试从数据函数返回this.colors.length

  2. Mobx会出于性能原因而在“交易”中批量更新,因此您不必一定会在每次更改后都在同一代码块中发生多个更改后看到反应。

  3. 通常,当您将元素添加到可观察数组时,新元素本身就可以被观察。使用asFlat会禁用此行为,但是当您的数组元素只是字符串时,将不会引起注意。

  4. 我猜您只是在查看控制台中记录的扩展对象,它可能显示该对象的当前值,而不是记录该对象时的值。尝试记录单个键,您应该看到记录时的值。

  5. 与问题(1)相同。简单的比较不会显示任何更改-更新返回this.config.model的数据函数,您应该会看到反应。

  6. 没问题。

The Mobx docs for reactions有一些很好的信息。 asReferenceasFlat在较新的版本中消失了,但等效于observable.refobservable.shallow。有关更多信息,请参见the docs