Запоминающийся селектор с вычислением в @ngrx/store

Мой нормализованный магазин ngrx выглядит так:

export interface State {
    carts: EntityState<Cart>;
    items: EntityState<Item>;
}

export interface Cart {
    id: number;
    maxVolume: number;
}

export interface Item {
    id: number;
    cartId: number;
    volume: number;
}

Это довольно простая установка, когда в корзине может быть несколько предметов. Мой селектор должен возвращать массив со всеми тележками с массивами, содержащими их товары, а также вычислять, есть ли опасность выпадения товаров из соответствующей корзины:

export const select: MemoizedSelector<object, any> = createSelector(
  selectAllCarts, selectAllItems, 
  (allCarts: Cart[], allItems: Item[]) => {
    return allCarts.map(c => {
      const items = allItems.filter(i => i.cartId == i.id);
      return {
        id: c.id,
        items: items.map(i => {
          // computations, should not run if cart's items have not changed
          // needs to be memoized
          const computed = isCartOverfilled(i, c, items);
          return {
            id: i.id,
            mightFallOut: computed//computed value needs to be output
          }
        })
      }
    });
});

Каждый раз, когда товар обновляется, isCartOverfilled запускается для каждого товара в магазине. Но isCartOverfilled потенциально затратен и зависит только от товаров внутри корзины. Когда элемент обновляется, например. добавляется в корзину, isCartOverfilled должен выполняться ТОЛЬКО для товаров внутри, т. е. запоминается по идентификатору корзины.

Как мне этого добиться?

Я попытался выбрать товары из одной корзины:

export const selectCart = (cartId: number) => createSelector(
  selectItemsByCartId(cartId), selectCartById(cartId),
  (items: Item[], cart: Cart) => {
  return {
    id: cart.id,
    items: items.map(i => {
      const computed = isCartOverfilled(i, cart, items);
      return {
        id: i.id,
        mightFallOut: computed
      }
    })
  }
});

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


person Ante Novokmet    schedule 03.01.2019    source источник


Ответы (1)


Поскольку состояние уже изменено, селектор пересчитает.

Но вы можете добиться этого, сохраняя другое состояние для корзины и когда вы отправляете действие addCart Item, вы можете обновить корзину одним товаром вместо использования селектора.

export interface State {
    carts: EntityState<Cart>;
    cartOverFilled: SomeState or part of Cart State <---
    items: EntityState<Item>;
}

or

export interface State {
    carts: EntityState<CartState>;
    items: EntityState<Item>;
}

export interface CartState {
    cart: Cart;
    overFilled: any
}

export interface Cart {
    id: number;
    maxVolume: number;
}
  1. Добавьте еще одно состояние со значениями для проверки на переполнение;
  2. Создайте эффект для ofType «Добавить в корзину»
  3. Создайте еще одно действие для пересчета существующего состояния переполнения входящим элементом.
person rijin    schedule 03.01.2019
comment
Я знаю о первом пункте. Что касается второго, вы предлагаете мне перенести вычисления в редуктор и фактически сохранить вычисленное состояние для сохранения? Есть ли способ создать такой селектор, который при пересчете пересчитывал бы только товары из одной корзины? - person Ante Novokmet; 03.01.2019
comment
Отправить другое действие - person rijin; 03.01.2019