I am trying to understand ngrx "selectors with props" [https://ngrx.io/guide/store/selectors#using-selectors-with-props]. There are two parts in the given links. The first part is clear to me and I could use it in my code. I could not understand the second part -
Keep in mind that a selector only keeps the previous input arguments in its cache. If you re-use this selector with another multiply factor, the selector would always have to re-evaluate its value. This is because it's receiving both of the multiply factors (e.g. one time 2, the other time 4). In order to correctly memoize the selector, wrap the selector inside a factory function to create different instances of the selector.
The following is an example of using multiple counters differentiated by id.
export const getCount = () =>
createSelector(
(state, props) => state.counter[props.id],
(counter, props) => counter * props.multiply
);
ngOnInit() {
this.counter2 = this.store.pipe(select(fromRoot.getCount(), { id: 'counter2', multiply: 2 }));
this.counter4 = this.store.pipe(select(fromRoot.getCount(), { id: 'counter4', multiply: 4 }));
this.counter6 = this.store.pipe(select(fromRoot.getCount(), { id: 'counter6', multiply: 6 }));
}
In above code, (state, props) => state.counter[props.id]
, part I could not understand. Can somebody help in understanding (state, props) => state.counter[props.id]
in combination with usage in ngOnInit
?
It appears to me that state.counter[props.id]
will return expected if counter
state has properties with name as id
i.e counter2
or counter4
.
The following link is also not explaining in details - https://blog.angularindepth.com/ngrx-parameterized-selector-e3f610529f8
A short example will be really helpful.
It returns the last cached value if it's subsequently called with same parameters.
export const getCount = () =>
createSelector(
(state, props) => state.counter[props.id],
(counter, props) => counter * props.multiply
);
ngOnInit() {
// Calculate selector params (counter2, 2) and return value
this.counter2 = this.store.pipe(select(fromRoot.getCount(), { id: 'counter2', multiply: 2 }));
// Calculate selector params (counter4, 4) and return value
this.counter4 = this.store.pipe(select(fromRoot.getCount(), { id: 'counter4', multiply: 4 }));
// Get Cached selector params (counter4, 4) and return value
this.counter5 = this.store.pipe(select(fromRoot.getCount(), { id: 'counter4', multiply: 4 }));
// Calculate selector params (counter6, 6) and return value
this.counter6 = this.store.pipe(select(fromRoot.getCount(), { id: 'counter6', multiply: 6 }));
// Calculate selector params (counter4, 4) and return value
this.counter8 = this.store.pipe(select(fromRoot.getCount(), { id: 'counter4', multiply: 4 }));
}
State will have shape we define in reducers that is created when AppModule is bootstrapping which will be update when Action is triggered.
export const initialState: State = {
home: 0,
away: 0,
};
const scoreboardReducer = createReducer(
initialState,
on(ScoreboardPageActions.homeScore, state => ({ ...state, home: state.home + 1 })),
on(ScoreboardPageActions.awayScore, state => ({ ...state, away: state.away + 1 })),
on(ScoreboardPageActions.resetScore, state => ({ home: 0, away: 0 })),
on(ScoreboardPageActions.setScores, (state, { game }) => ({ home: game.home, away: game.away }))
);
export function reducer(state: State | undefined, action: Action) {
return scoreboardReducer(state, action);
}
Your assumption is right, state is passed on selector
(the first parameter).
It appears to me that state.counter[props.id] will return expected if counter state has properties with name as id i.e counter2 or counter4.