MobX полный пересчет на чтение, хотя наблюдаемые не меняются? - PullRequest
0 голосов
/ 20 июня 2019

У меня есть магазин mobx, который выглядит как

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;
  }
}

Это дорогостоящее вычисленное значение с дочерними вычисляемыми значениями, которое вызывается в цикле requestAnimationFrame, который вызывает entityStore.renderPayload() со скоростью 60 кадров в секунду. Мне нужно, чтобы это было кэшировано.

используя trace я получил вывод [mobx.trace] 'EntityStore@1.renderPayload' is being read outside a reactive context. Doing a full recompute

Это удивляет меня, так как мои ожидания были, что Mobx будет только пересчитывать, если изменятся зависимые наблюдаемые величины к вычисленному значению.

Есть ли способ заставить это не пересчитать поведение?

Обновление Я не использую реагирую. это обычные объекты MOBX

1 Ответ

1 голос
/ 20 июня 2019

Обычно такое поведение наблюдается при попытке доступа к значению без использования observer (или reaction, или autorun).Вы не упоминаете, используете ли вы React или другую библиотеку, или объясняете, как вы получаете доступ к значению.Возможно, стоит установить минимальный пример на CodeSandbox или аналогичный, который воспроизводит проблему, с которой вы сталкиваетесь.

Если бы мне пришлось размышлять, я бы сказал, что вы потребляете свои вычисленныезначение где-то в компоненте, который не заключен в observer (в случае React). Вот пример (с удалением неиспользуемых методов), который воспроизводит проблему без дополнительной инфраструктуры:

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 или подобного.Если вы уверены, что это не так, возможно, добавьте еще несколько деталей к вопросу.

...