1
votes

Angular / Rxjs exécutent les appels de magasin (ngrx) de manière synchrone

J'ai besoin d'effectuer une action, après avoir récupéré 2 objets de ma boutique (ngrx), donc, j'ai besoin que les deux appels aient répondu avant d'effectuer mon action, comme ceci:

const item1$: Observable<Item> = this._store$.select(
  ItemStoreSelectors.selectItemById(this.id1)
);

const item2$: Observable<Item> = this._store$.select(
  ItemStoreSelectors.selectItemById(this.id2)
);

let item1: Item;
item1$.pipe(take(1)).subscribe((item: Item) => {
  item1 = item;
});

let item2: Item;
item2$.pipe(take(1)).subscribe((item: Item) => {
  item2 = item;
});

// here, items might not have been initialized
doSomething(item1, item2);

I a essayé de chercher une solution dans rxjs avec switchMap, mergeMap, etc., mais ne pouvait pas l'appliquer à mes besoins. Je pense avoir trouvé une solution en faisant async / await, mais je ne suis pas sûr que ce soit une bonne pratique.

Merci pour votre aide.


3 commentaires

utilisez combineLatest learnrxjs.io/operators/combination/combinelatest.html


ou selon le cas ... forkJoin .


@MoxxiManagarm va examiner ça, merci, j'ai déjà essayé je pense mais je n'ai pas pu le faire fonctionner avec mon cas


3 Réponses :


3
votes

Refactoriser dans le code suivant:

import { forkJoin } from 'rxjs';

const item1$: Observable<Item> = this._store$.select(
  ItemStoreSelectors.selectItemById(this.id1)
);

const item2$: Observable<Item> = this._store$.select(
  ItemStoreSelectors.selectItemById(this.id2)
);

forkJoin([item1$.pipe(take(1)), item2$.pipe(take(1))])
   .subscribe(([item1,item2])=>doSomething(item1,item2));
  


2 commentaires

merci ça a l'air génial, donc si je comprends bien, l'abonnement ne se déclenchera que lorsque les deux éléments auront été déclenchés?


Correct, forkJoin crée une observable qui émet la dernière valeur de ses sources une fois qu'elles sont toutes terminées.



1
votes

combineLatest sera déclenché à chaque fois qu'un des feux observables, si c'est ce que vous voulez, essayez ceci:

item1$: Observable<Item> = this._store$.select(
  ItemStoreSelectors.selectItemById(this.id1)
);

item2$: Observable<Item> = this._store$.select(
  ItemStoreSelectors.selectItemById(this.id2)
);

result$: Observable<any> = combineLatest(this.item1$, this.item2$, this.doSomething());


1 commentaires

merci aussi, je vais examiner la différence entre combineLatest et forkJoin en tant que @Jota. Toledo a répondu mais je pense que cela ne répond pas complètement à mes besoins car j'ai besoin d'une pipe (prenez (1))



0
votes

Vous pouvez également utiliser withLatestFrom dans un effet. Quelque chose comme ça

@Effect()
  myAction$ = this.actions$.pipe(
    ofType<MyAction>(MyActionTypes.MyAction),
    withLatestFrom(this.store.select(mySelector)),
    withLatestFrom(this.store.select(myOtherSelector)),
    exhaustMap(([[action, item1], item2]) =>
      this.myService.myRequest(/*...*/)
      .pipe(
        map(myResult => new GetResultSuccess(myResult)),
        catchError(error => of(new GetResultFailure(error))),
      ),
    ),
  );


0 commentaires