Day 7: Higher-Order Mapping (mergeMap, switchMap)
Day 7: Higher-Order Mapping
This is it. The hurdle where most people quit RxJS. But we’ll make it simple.
The Problem:
You have an Observable of User IDs. For each ID, you want to make an HTTP call (which returns another Observable).
If you just use map, you get an Observable<Observable<Data>>. You want just Observable<Data>.
You need to flatten the inner stream.
1. mergeMap (Parallel)
Subscribe to EVERY new inner observable as it arrives. Do not cancel anything. Use case: Delete items in parallel.
import { from, of } from 'rxjs';
import { mergeMap, delay } from 'rxjs/operators';
// Simulate API call
const deleteItem = (id) => of(`Deleted ${id}`).pipe(delay(1000));
from([1, 2, 3]).pipe(
mergeMap(id => deleteItem(id))
).subscribe(console.log);
// Output: (After 1s) "Deleted 1", "Deleted 2", "Deleted 3" (Almost simultaneous)
2. switchMap (Cancel Previous)
If a new value arrives, unsubscribe from the previous inner observable and subscribe to the new one. Use case: Search Typeahead. If user types “a” then “ab”, cancel the search for “a” and only search “ab”.
import { fromEvent, interval } from 'rxjs';
import { switchMap } from 'rxjs/operators';
// Restart the interval on every click
fromEvent(document, 'click').pipe(
switchMap(() => interval(1000))
).subscribe(console.log);
// If you click, it restarts counting from 0.
3. concatMap (Queue)
Wait for the previous inner observable to complete before starting the next. Use case: Sequential updates where order matters.
import { from, of } from 'rxjs';
import { concatMap, delay } from 'rxjs/operators';
const saveItem = (id) => of(`Saved ${id}`).pipe(delay(1000));
from([1, 2, 3]).pipe(
concatMap(id => saveItem(id))
).subscribe(console.log);
// Output:
// ...wait 1s... "Saved 1"
// ...wait 1s... "Saved 2"
// ...wait 1s... "Saved 3"
4. exhaustMap (Ignore new)
If an inner observable is running, ignore all new synchronous source values. Use case: “Login” button. Don’t let user spam-click it while request is pending.
Homework for Day 7:
- Create a
click$observable. - Use
switchMapto trigger an API call (simulated withtimer(2000)). - rapid-click the button. Verify that only the LAST click results in a console log.
Day 8: Subject & Multicasting!