Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to select a single object by id using @ngrx/entity

Using @ngrx/entity I want to select an entity by a single id or an array of entities by an array of ids from an entity map.

I do not want the select subscriptions inside a component to be triggered when the entity collection gets a new element or an entity item changes, which I did not select at all.

This obviously happens to me when I use the selectEntities selector and then pick the IDs from the result.

So how can I select 1 or n items by id from an entity collection?

like image 987
vachee Avatar asked Apr 09 '18 15:04

vachee


People also ask

What is a good use case for NgRx entity?

business data, such as for example Courses or Lessons, in the case of an online course platform. some UI state, such as for example UI user preferences.

When should I use NgRx data?

Quoting NgRx Data documentation, typical usage of this library is entity data management. Basically it means that if you have complex entity collection you should go hard way and use @ngrx/entity where the boilerplate code is huge.

What is the use of selector in NgRx?

Selectors are pure functions used for obtaining slices of store state. @ngrx/store provides a few helper functions for optimizing this selection. Selectors provide many features when selecting slices of state: Portability.


2 Answers

EDIT: as Ethan mentions below, selectors with props were deprecated in v12. This decision was discussed extensively in an RFC. (Comments further down the thread address how to effectively memoise factory functions.)

The currently recommended approach to this is using a factory function:

export const selectEntity = id => createSelector(
  selectEntities,
  entities => entities[id]
);

export const selectEntitiesByID = ids => createSelector(
  selectEntities,
  entities => ids.map(id => entities[id])
);

Which are called thus:

this.store.pipe(
  select(selectEntity(someID))
);

this.store.pipe(
  select(selectEntitiesByID(arrayOfIDs))
);

Previously, NgRx supported parameterised selectors by passing props as the last argument to a selector function:

export const selectEntity = createSelector(
  selectEntities,
  (entities, props) => entities[props.id]
);

export const selectEntitiesByID = createSelector(
  selectEntities,
  (entities, props) => props.ids.map(id => entities[id])
);

These are invoked exactly as you might expect:

this.store.pipe(
  select(selectEntity, { id: someID })
);

this.store.pipe(
  select(selectEntitiesByID, { ids: arrayOfIDs })
);
like image 190
Jordan Gray Avatar answered Sep 18 '22 09:09

Jordan Gray


Selectors with props are deprecated, for more info see RFC: Deprecate Selectors With Props.

However, a type safe alternative is demonstrated in RFC 2980. Applied to the answer from @jordan-gray:

export const selectEntity = (props: { id: number }) =>
  createSelector(selectEntities, (entities) => {
    return entities[props.id];
  });

Called with

this.store.select(selectEntity({ id: myId }));
like image 37
Jack Avatar answered Sep 21 '22 09:09

Jack