Мемоизированный селектор с вычислением в @ ngrx / store - PullRequest
0 голосов
/ 03 января 2019

Мой нормализованный магазин 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
      }
    })
  }
});

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

1 Ответ

0 голосов
/ 03 января 2019

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

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

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

или

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