MobX在读取时完全重新计算,尽管可观察性没有变化?

时间:2019-06-20 05:29:58

标签: javascript mobx

我有一个看起来像mobx的商店

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
  <input type="hidden" class="check_sales_pack" name="check_sales_pack">
  <input type="number" class="qty_pack" name="qty_pack" value="0" min="0" max="3">
  <input type="number" class="qty_pack" name="qty_pack" value="0" min="0" max="3">
</div>

这是一个昂贵的计算值,带有子计算值,会在class EntityStore { rootStore @observable entityIndex = {} constructor(rootStore){ this.rootStore = rootStore; } @action addEntities(entityArray){ entityArray.forEach((entity) => this.addEntity(entity)); } @action addEntity(entityProps){ if(entityProps.id && this.entityIndex[entityProps.id]){ throw new Error(`Failed to add ${entityProps.id} an entity with that id already exists`); } const entity = new Entity({ ...entityProps, assetStore: this.rootStore.assetStore, regl, }); this.entityIndex[entity.id] = entity; } @computed get entityAssetIds(){ return Object.values(this.entityIndex).map(e => e.assetId); } @computed get renderPayload(){ const payloadArray = []; for(let entityId in this.entityIndex){ payloadArray.push(this.entityIndex[entityId].renderPayload) } return payloadArray; } } 循环中以60fps的速度调用requestAnimationFrame进行调用。我需要将其缓存。

使用entityStore.renderPayload(),我得到了输出 trace

这让我感到惊讶,因为我的期望是Mobx仅在对计算值的依赖观测值发生更改时才会重新计算。

有什么办法强迫这种不可重新计算的行为吗?

更新我不使用反应。这是普通的mobx对象

2 个答案:

答案 0 :(得分:1)

通常是您尝试使用不使用observer(或reactionautorun)的值时看到的行为。您不会提及您使用的是React还是其他库,也不会说明您如何访问该值。可能值得在CodeSandbox上建立一个最小的示例来重现您遇到的问题。

如果我不得不推测,我想说的是,您正在将计算值消耗在没有用observer包装的组件中的某个位置(对于React)。 Here's一个示例(删除了未使用的方法)无需其他框架即可重现该问题:

import { autorun, computed, configure, observable } from "mobx";

class EntityStore {
  @observable entityIndex = {};

  @computed get renderPayload() {
    const payloadArray = [];
    for (let entityId in this.entityIndex) {
      payloadArray.push(this.entityIndex[entityId].renderPayload);
    }
    return payloadArray;
  }
}
configure({ computedRequiresReaction: true });

const store = new EntityStore();

// console.log('THIS WILL TRIGGER A WARNING:', store.renderPayload)

autorun(() => console.log('THIS WILL NOT TRIGGER A WARNING:', store.renderPayload))

如果取消注释日志,则应该看到控制台警告。可能是,您在observer内或类似地方之外使用了计算值。如果您确定不是这种情况,则可以在问题中添加更多细节。

答案 1 :(得分:1)

Mobx不错,就像您在示例中的回购中将其命名一样,它真棒,它不会重新计算任何代码都未观察到的值。

要修正您的示例,只需在setInterval前面加上这一行

observe(M, 'output', () => {})

现在MobX知道可以观察到输出,并且您的昂贵计算将只运行一次。直到一些相关的变量更改。

只需在开始动画循环之前观察使用的计算域,并在结束后进行处理,就可以像魔术一样工作。