web-dev-qa-db-fra.com

sélecteurs ngrx avec filtres

J'utilise @ngrx dans une application Angular et j'aimerais résumer l'un des modèles récurrents que j'ai déjà.

Mon état est généralement composé de nombreux états comme celui-ci:

myState: {
  data: any
  isLoading: boolean
  isLoaded: boolean
}

donc ce que je finis par faire dans le code est de m'y abonner mais je veux seulement être averti si l'état a été chargé.

this.store
  .select(state => state.myState)
  .filter(myState => myState.isLoaded)
  .map(myState => myState.data)
  .do(data => do_whatever_I_need_to_do)
  .subscribe();

cela fonctionne pour moi, mais je me demandais si je pouvais simplifier les 3 premiers opérateurs car ils sont assez récurrents.

En utilisant des sélecteurs, je pouvais créer quelque chose comme ça

const selectMyState = (state) => state.myState;

export const getData = createSelector(selectMyState, state => state.data)

puis l'utiliser comme ça

this.store
  .select(getData)
  .do(data => do_whatever_I_need_to_do)
  .subscribe();

mais alors il me manque la partie filtre, donc je pourrais en obtenir des événements de flux même si mes données n'ont pas encore été chargées.

Existe-t-il un moyen d'inclure ce filtre manquant dans l'observable? Je sais que createSelector a une fonction en tant que paramètre, de sorte que je puisse y faire du code, mais je ne sais pas comment je l'utiliserais pour filtrer non pas les données, mais l'événement lui-même.

Des idées? Merci!

7
David

Pour ce type de scénario où je veux réutiliser une partie d'un flux, je crée une fonction qui accepte le magasin en tant que paramètre et effectue certaines opérations dessus. Ce qui suit est un exemple:

const selectMyState = (state) => state.myState;
export const getData = createSelector(selectMyState, state => state.data)
export const getDataWhenLoaded = (store) => {
    return store.select(getData)
        .filter(myState => myState.isLoaded);
};
...
getDataWhenLoaded(this.store).subscribe(...);

En ce qui concerne l'utilisation du dernier paramètre de la fonction createSelector, vous pouvez le faire en fonction de vos besoins. Dans le documentation il mentionne que le même état passé au sélecteur mémorisé créé par createSelector ne recalculera pas la projection. Il renverra la même valeur lors de son appel. Je n'ai pas pu trouver de documentation à ce sujet mais à travers les tests, j'ai remarqué que si la projection donne la même valeur que la valeur précédente, elle ne sera pas émise si l'abonnement a déjà reçu la valeur précédente. Comportement similaire à l'opérateur rxjs distinctUntilChanged. Je n'ai pas eu le temps de fouiller dans leur code source pour comprendre où/comment/pourquoi.

Donc, dans certains cas, vous pouvez mettre un filtre dans le paramètre de projection (dernier) pour createSelector. Voici un exemple:

export const getActive = createSelector(selectMyData, state => state.data.filter(x => x.isActive));
4
bygrace

L'exemple provient de ngrx.io

En supposant que vous disposez du sélecteur selectValues ​​et que vous souhaitez filtrer les valeurs rendant le code réutilisable.

import { select } from '@ngrx/store';
import { pipe } from 'rxjs';
import { filter } from 'rxjs/operators';

export const selectFilteredValues = pipe(
 select(selectValues),
 filter(val => val !== undefined)
);

store.pipe(selectFilteredValues).subscribe(/* .. */);
3
Max Epelbaum