Request po zakończeniu drugiego [Typescript/rxjs]

0

Mam następujący przypadek: najpierw muszę z jednego requestu uzyskać productId

    private loadCart(cartId: string): void {
        if (cartId) {
            this.api.get(cartId).subscribe(result => {
                this.productId = result.productId;
            });
        }
    }

Następnie konieczne jest wykonanie request na podstawie productId:

        this.productService.getDetails(this.productId).subscribe(result => {
            this.threshold = result.threshold;
        });

Rozumiem, że wykonywanie go w środku tamtego requestu nie wyglądałoby najlepiej. Pytanie, czy jest jakiś operator, który skutecznie pozwoliłby na wykonanie jednego requestu zaraz po tym jak skończy się drugi? Z tego co widzę, concatmap może się do tego przydać. Prosiłbym o weryfikację czy dobrze kminię.

1

imo powinienes zrobic to w subscribe.

Jezeli Ci sie zmieni this.productId to wtedy od razu wykonasz kolejny request

 private loadCart(cartId: string): void {
        if (cartId) {
            this.api.get(cartId).subscribe(result => {
                this.productId = result.productId;
                this.productService.getDetails(this.productId).subscribe(productResult => {
                    this.threshold = productResult .threshold;
                });
            });
        }
    }
0

Dzięki. Co prawda flow jest takie, że po wejściu do komponentu ten productId zostaje dokładnie taki sam i już więcej nie jest ten request wywołany. Czy w takim razie nadal lepiej tak zostawić?

0

Nie powinno się robić subscribe w subscribe. Lepszym rozwiązaniem będzie użycie combineLatest albo with LatestFrom.

0

Nie znam się za bardzo na rxJS ale concatMap (https://www.learnrxjs.io/operators/transformation/concatmap.html) wygląda jak coś czego potrzebujesz.

0

Zrobiłem to w taki sposób:

            const requests = of(this.api.get(cartId).pipe(tap(result => {
                this.productId = resultproductId;
            })), this.productService.getDetails(this.productId).pipe(tap(result => {
                this.threshold = result.threshold;
            })));

            requests.pipe(concatMap(request => of(console.log(request)))).subscribe();

Jednak niestety requesty nie lecą do API. mógłby ktoś podpowiedzieć, w jaki sposób sprawnie to poprawić? Starałem się korzystać z dokumentacji.

1

Raczej coś w stylu :

this.api.get(cartId).pipe(
switchMap(p=>this.productService.getDetails(p.productId))).subscribe(result=>{
this.threshold = result.threshold
});

Co ważne - unikaj zapisywania efektów z tap do zmiennych poza pipe. Podobnie unikaj przekazywania do parametrów z zewnatrz potoku do jego wnetrza. RxJS został stworziny wjako programowanie funkcyjne - potok działa jak funkcja i nie powienien powodowac side-effectów. Masz wejście i kierujesz je do wyjścia nie zmieniając stanu aplikacji. Zmienic stan możesz dopiero w subscribe.

2

@darkrat:
Powinieneś wykorzystać operator 'toPromise()'
w wersji async/await

private async loadCart(cartId: string): void {
    if (cartId) {
        const { productId } = await this.api.get(cartId).toPromise();
        const { threshold } = await this.productService.getDetails(productId).toPromise();
        this.threshold = threshold;
    }
}

i promise

private loadCart(cartId: string): void {
    if (cartId) {
        this.api.get(cartId).toPromise()
            .then(result => this.productService.getDetails(result.productId).toPromise())
            .then(result => {
                this.threshold = result.threshold;
            })
            .catch(e => {
                // ...            
            }
            
    }
}
0

Dzięki za odpowiedź @kult. Zastanawiam się, jaką to rozwiązanie ma przewagę nad concatmap, którego finalnie użyłem?

1 użytkowników online, w tym zalogowanych: 0, gości: 1