Platform: ComponentStore: Allow multiple selector functions to store.select

Created on 22 Dec 2020  路  7Comments  路  Source: ngrx/platform

Currently, store.select can either be passed a selector function, or alternately multiple selectors can be combined by passing 2 or more selectors with a project function. It would be convenient if each of the "combine selectors" could accept either a selector or a function, in order to concisely select multiple properties from the state that don't already have selectors defined:

this.store.select(
  state => state.foo,
  state => state.bar,
  (foo, bar) => ({ foo, bar })
 );

Basically, if the select function encounters a function as one of the arguments instead of an observable, all it would have to do is wrap the function internally with this.select(selectorFn)

Signature for the overload for two selectors would be something like

select<R, S1, S2>(
    s1: Observable<S1> | (s: T) => S1, 
    s2: Observable<S2> | (s: T) => S2,
    projector: (s1: S1, s2: S2) => R, 
   config?: SelectConfig
): Observable<R>;

Describe any alternatives/workarounds you're currently using

this.store.select(
  this.store.select(state => state.foo),
  this.store.select(state => state.bar),
  (foo, bar) => ({ foo, bar })
 );
Component Store

Most helpful comment

Generally, I like the idea. @timdeschryver @markostanimirovic maybe we can explore it past v11?

All 7 comments

Note that @ngrx/store supports this.

from https://ngrx.io/guide/store/selectors#using-selectors-for-multiple-pieces-of-state:

export const selectUser = (state: AppState) => state.selectedUser;
export const selectAllBooks = (state: AppState) => state.allBooks;

export const selectVisibleBooks = createSelector(
  selectUser,
  selectAllBooks,
  (selectedUser: User, allBooks: Book[]) => {
    if (selectedUser && allBooks) {
      return allBooks.filter((book: Book) => book.userId === selectedUser.id);
    } else {
      return allBooks;
    }
  }
);

Since this is the state of a component, I'm not sure if we need this.
What would be the benefit of this, in comparison to simply selecting those props from the state?

vm$ = this.store.select(state => ({  foo: state.foo, bar: state.bar }))

What would be the benefit of this, in comparison to simply selecting those props from the state?

vm$ = this.store.select(state => ({  foo: state.foo, bar: state.bar }))

This will emit a new value every time the state changes, even if foo and bar haven't changed. The selector creates a new object, so the internal call to distinctUntilChanged emits every time.

Take a look here to see this in action: https://stackblitz.com/edit/ngrx-component-store-selectors?file=src/app/app.component.ts&devtoolsheight=50 (observe the console to see logging output. Selector A is output multiple times, but selector B is only output once)

This actually could be documented better to ensure other devs understand the difference.

@timdeschryver @alex-okrushko I can take this one

IIRC, we discussed this when the implementation was on going, but I can't find it anymore...
I think we decided not to do it because it shouldn't be a big performance hit in combination that it would require more code (and we would want to use the existing selectors).

Generally, I like the idea. @timdeschryver @markostanimirovic maybe we can explore it past v11?

Sounds good to me 馃憤

Was this page helpful?
0 / 5 - 0 ratings