web-dev-qa-db-fra.com

ngrx: comment passer des paramètres au sélecteur à l'intérieur de la méthode createSelector

J'ai un état très simple dans mon magasin:

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

J'ai un sélecteur pour les enregistrements:

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

Et ce que je veux maintenant, c'est avoir des sélecteurs séparés pour récupérer chaque enregistrement par index. À cette fin, je veux créer un sélecteur générique avec des accessoires de cette manière:

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

Et après cela, créez quelques sélecteurs spécifiques e. g.:

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

Mais je n'ai trouvé aucune mention sur la façon de passer des paramètres aux sélecteurs avec des accessoires lorsque nous les utilisons dans la méthode createSelector. C'est possible?

9
user3429127

De cet article de blog: https://blog.angularindepth.com/ngrx-parameterized-selector-e3f610529f8

Depuis NgRx 6.1, les sélecteurs acceptent également un argument d'accessoires supplémentaires. Ce qui signifie que vous pouvez maintenant définir un sélecteur comme suit:

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

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

Ah ... mais en relisant votre question, vous vous demandez alors comment construire un autre sélecteur qui utilise ce sélecteur? L'article ci-dessus propose de créer une fonction d'usine.

7
DeborahK

J'utilise "@ngrx/entity": "7.2.0", et je peux voir que les accessoires sont passés à chaque sélecteur, par exemple dans mon composant que j'appelle:

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

Et puis dans mon réducteur j'ai les éléments suivants:

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;
  }
);
2
Ian Jamieson

Vous pouvez utiliser la fonction projecteur:

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 })
);
0
grahamaj

Avec des paramètres fixes pour le sélecteur, cela fonctionne bien:

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

mais qu'en est-il des paramètres dynamiques:

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

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

cela ne fonctionnait pas dans mon application :-( (NgRx version 8)

0
Reinhard