Observable streams - one to many vs many to one

228 Views Asked by At

How to store a list of items when items can exist in different modules?

One state to items or Multi states to items? I assume there will be a lot of different modules that will store items and the more of these modules, the more I want to move away from one state

One state

class Item {
  id: number;
  name: string;
  location: "equipment" | "magazine" | "shop"  // | and other in future...
}

class AppState {
  items: Item[];
}

const getItems = (store: Store): Observable<Item[]> => {
  return store.select((appStore: AppStore) => appStore.items);
}

const getItemsInEquipment = (store: Store): Observable<Item[]> => {
  const items$: Observable<Item[]> = getItems(store);
  return items$.pipe(
    map(items => items.filter(item => item.location === "equipment"))
  );
}

const getItemsInMagazine = (store: Store): Observable<Item[]> => {
  const items$: Observable<Item[]> = getItems(store);
  return items$.pipe(
    map(items => items.filter(item => item.location === "magazine"))
  );
}

const getItemsInShop = (store: Store): Observable<Item[]> => {
  const items$: Observable<Item[]> = getItems(store);
  return items$.pipe(
    map(items => items.filter(item => item.location === "shop"))
  );
}

or...

Multi states

class Item {
  id: number;
  name: string;
}

class AppState {
  itemsInEquipment: Item[];
  itemsInMagazine: Item[];
  itemsInShop: Item[];
  // | and other in future...
}

const getItemsInEquipment = (store: Store): Observable<Item[]> => {
  return store.select((appStore: AppStore) => appStore.itemsInEquipment);
}

const getItemsInMagazine = (store: Store): Observable<Item[]> => {
  return store.select((appStore: AppStore) => appStore.itemsInMagazine);
}

const getItemsInShop = (store: Store): Observable<Item[]> => {
  return store.select((appStore: AppStore) => appStore.itemsInShop);
}

const getItems = (store: Store): Observable<Item[]> => {
  const itemsInEquipment$: Observable<Item[]> = getItemsInEquipment(store);
  const itemsInMagazine$:  Observable<Item[]> = getItemsInMagazine(store);
  const itemsInShop$:      Observable<Item[]> = getItemsInShop(store);
  return combineLatest([itemsInEquipment$, itemsInMagazine$, itemsInShop$]);
}

What are the advantages and disadvantages of both approaches?

1

There are 1 best solutions below

0
On

I would suggest a different approach. In NgRx, for example, we would set up a single Entity state for all Items, and then simply store arrays of the IDs of the Items in each list. NGXS Labs has an Entity state adapter that might be worth trying.

Basically, you have all of your Items stored in an Object, where the keys are the id field for each Item:

itemEntities: {
  itemId1: Item,
  itemId2: Item,
  itemId3: Item
}

This allows for direct lookup, and prevents performance losses caused by Array actions.

Then, each of your itemsInEquipment, itemsInStore etc are all simple Arrays of ids, allowing you to grab them from the Entity state.