ngrx: how to pass parameters to selector inside cr

2020-07-02 09:44发布

问题:

I have a very simple state in my store:

const state = {
 records: [1,2,3],
};

I have a selector for records:

export const getRecords = createSelector(getState, (state: State) => state.records));

And what I want now is to have separate selectors for fetching each record by index. For this purpose I want to create one generic selector with props in this way:

export const getRecordByIndex = createSelector(
getRecords,
(state: State, { index }) => state.records[index]),
);

And after that create a couple of specific selectors e. g.:

export const getFirstRecord = createSelector(
getRecordByIndex(/* somehow pass index = 0 to this selector */),
(firstRecord) => firstRecord),
);

But I didn't find any mention how to pass parameters to selectors with props when we use them inside createSelector method. Is it possible?

回答1:

From this blog post: https://medium.com/angular-in-depth/ngrx-parameterized-selector-e3f610529f8

As of NgRx 6.1 selectors also accepts an extra props argument. Which means you can now define a selector as the following:

export const getCount = createSelector(
  getCounterValue, 
  (counter, props) => counter * props.multiply
);

this.counter = this.store.pipe(
  select(fromRoot.getCount, { multiply: 2 })
);

Ah ... but rereading your question, you are asking then how to build another selector that uses this selector? The above-linked article suggests building a factory function.



回答2:

I am using "@ngrx/entity": "7.2.0", and I can see that props are passed to each selector, for example in my component I am calling:

this.isActive$ = this.store.pipe(select(fromClient.isActive, { id: 'someid' }));

And then in my reducer I have the following:

export const getClientState = createFeatureSelector<ClientState>('client');

export const getClient = createSelector(
  getClientState,
  (state, props) => {
    // do something with props.id to get the client then:
    return state;
  }
);

export const isActive: = createSelector(
  getClient, // props are passed to here
  (state: any) => { // i don't add the props argument here, as i don't need them
    return state.isActive;
  }
);


回答3:

You could use the projector function:

export interface Record {
  // Some sort of record interface
}

export interface State {
  records: Record[];
}

export const getRecords = createSelector(
  getState,
  (state: State): Record[] => state.records)
);

export const getRecordByIndex = createSelector(
  getRecords,
  (records: Record[], { index }) => records[index]),
);

export const getFirstRecord = createSelector(
  getRecords,
  (records: Record[]) => getRecordByIndex.projector(records, { index: 0 })
);


回答4:

With fixed parameters for the selector it works fine:

this.counter = this.store.pipe(
    select(fromRoot.getCount, { multiply: 2 })
);

but what's about dynamic parameters:

this.counter = this.store.pipe(
   select(fromRoot.getCount, { multiply: this.getMultiplier() })
);

getMultiplier() {
    ...
    return myUser.multiplier + magicFactor;
}

that did not work in my app :-( (NgRx version 8)



标签: angular ngrx