Home > Mobile >  Rxjs how to use mergeMap?
Rxjs how to use mergeMap?

Time:12-24

The task

I have 3 observable http1$ http2$ http3$ which are http requests.

const http1$ = this.myService.someFnReturnAnObservale({});

I have another observable isAuth$ as my stream source. I need to get response from http3$.

Context

In order to make http3$, http2$ have to response something first. Depend on isAuth$ value, if it emits true then http2$ also has to wait http1$ to response something, if it emits false, then no need http1$.

By something I mean either success or error, so I can apply some logic to it, and decide to stream to next observable or not.

Coding

  • create an observable to handle logic from http2$ to http3$
const http23$ = http2$.pipe(
    first(),
    map(res => {
       // some logic, return boolean flag
    }),
    catchError(err => {
        return of(false); // in case http2$ response with error, also return false
    }),
    map(res => {
        // if response (which is the flag above) is false
        // pop an message
        return res;
    }),
    filter(res => res === true), // only subscribe to http3$ after this
    mergeMap(res => http3$),
);
  • I have 2 logic with the isAuth$, so:
const initWithoutAuth$ = of(http23$); // no need http1$
const initWithAuth$ = http1$.pipe(
    first(),
    map(res => {
        // some logic, return boolean flag
    }),
    catchError(err => {
        return of(false); // in case http1$ response with error, also return false
    }),
    map(res => {
        // if response (which is the flag above) is false
        // pop an message

        return res;
    }),
    filter(res => res === true), // only subscribe to http23$ after this
    mergeMap(res => http23$)
);
  • Whenever isAuth$ emits new value, I'd like to cancel the current stream and start using another
isAuth$.pipe(
    switchMap(res => // does this really cancel curernt stream (http requests) to start over within the other one?
        res ? initWithAuth$ : initWithoutAuth$
    )
).subscribe(
    res => {
        console.log(`init`, res); // not the desired result yet
    },
    err => {}
);
  • I expect http3$ response when I subscribe at last step, but I got a weird observable.
  • How can I handle http observable response error properly in this situation? (duplicated code whenever I try to handle response and catch error of previous one)

CodePudding user response:

What I think is wrong is this line

const initWithoutAuth$ = of(http23$);

With this line you basically say that initWithoutAuth$ is an Observable which notifies (emits) another Observable, i.e. it notifies http23$.

It looks to me that initWithoutAuth$ should be simply set to http23$ and not to of(http23$).

If you do this, you can also remove catchError from initWithAuth$ and initWithoutAuth$ and add it to the final Observable chain, like this

isAuth$.pipe(
    switchMap(res => // does this really cancel curernt stream (http requests) to start over within the other one?
        res ? initWithAuth$ : initWithoutAuth$
    ),
    catchError(err => {
        return of(false); // in case http1$ or http2$ response with error, also return false
    }),
).subscribe(
    res => {
        console.log(`init`, res); // not the desired result yet
    },
);

As last note. I think that the last operator you use after each http call is not required. The http client returns an Observable which notifies at most just 1 value and then completes, so the last operator is redundant.

  • Related