← Back to list

Understanding map, switchMap, and exhaustMap in NgRx Effects: A Guide to Stream Transformation

The differences between exhaustMap, map, and switchMap in the context of NgRx effects:

Louis Trinh · 2025-02-02 23:02 · 1 claps · 3.2 min read
#maps #switchmap #exhaustmap #angular #ngrx
Open on Medium ↗
Wiki topics: 🌐 · Web Development

Understanding map, switchMap, and exhaustMap in NgRx Effects: A Guide to Stream Transformation

The differences between exhaustMap, map, and switchMap in the context of NgRx effects:

map

Purpose: Transforms each emission from an Observable into a new value.

Behavior:

  • Applies the provided function to each value emitted by the source Observable.
  • The resulting values form a new Observable.

Use Cases:

  • Modifying data within an Observable stream (e.g., multiplying numbers, converting strings).
  • Filtering out specific values (using conditional logic within the function).
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { increaseByTwo } from '../actions/counter.actions';
import { map } from 'rxjs/operators';
@Injectable()
export class CounterEffects {
  countByTwo$ = createEffect(() =>
    this.actions$.pipe(
      ofType(increaseByTwo),
      map((action) => action.payload * 2) // Double the payload
    )
  );
  constructor(private actions$: Actions) {}
}

switchMap

Purpose: Cancels any ongoing inner Observable subscription and subscribes to a new one based on the latest emission.

Behavior:

  • When the source Observable emits a value, switchMap unsubscribes from any currently active inner Observable subscription (if any).
  • It then subscribes to a new inner Observable returned by the provided function, using the emitted value as input.
  • Only the emissions from the latest inner Observable are emitted by the resulting Observable.

Use Cases:

  • Replacing an ongoing action with a new one based on the latest emission (e.g., fetching data for a newly selected user).
  • Handling side effects that should only occur once per emission (e.g., making a single API call for each user action).
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { loadUser, loadUserSuccess } from '../actions/user.actions';
import { switchMap } from 'rxjs/operators';
import { of } from 'rxjs'; // For error handling (optional)
@Injectable()
export class UserEffects {
  loadUser$ = createEffect(() =>
    this.actions$.pipe(
      ofType(loadUser),
      switchMap((action) =>
        this.userService.getUser(action.payload.userId).pipe(
          map((user) => loadUserSuccess({ user })),
          catchError((error) => of(loadUserFailure({ error }))) // Optional error handling
        )
      )
    )
  );
  constructor(private actions$: Actions, private userService: UserService) {}
}

exhaustMap

Purpose: Similar to switchMap, but ignores any subsequent emissions from the source Observable while the inner Observable is active.

Behavior:

  • When the source Observable emits a value, exhaustMap unsubscribes from any currently active inner Observable subscription (if any).
  • It then subscribes to a new inner Observable returned by the provided function, using the emitted value as input.
  • Only the emissions from the latest inner Observable are emitted by the resulting Observable.
  • If another emission occurs from the source Observable before the inner Observable completes, that emission is discarded.

Use Cases:

  • Preventing multiple side effects (e.g., API calls) from being triggered due to rapid user input (e.g., search queries).
  • Ensuring only one action is processed at a time, especially when actions might trigger long-running operations.
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { searchProducts, searchProductsSuccess } from '../actions/products.actions';
import { exhaustMap } from 'rxjs/operators';
import { of } from 'rxjs'; // For error handling (optional)
@Injectable()
export class ProductEffects {
  searchProducts$ = createEffect(() =>
    this.actions$.pipe(
      ofType(searchProducts),
      exhaustMap((action) =>
        this.productService.searchProducts(action.payload.searchTerm).pipe(
          map((products) => searchProductsSuccess({ products })),
          catchError((error) => of(searchProductsFailure({ error }))) // Optional error handling
        )
      )
    )
  );constructor(private actions$: Actions, private userService: UserService) {}
}

Choosing between map, switchMap, and exhaustMap in NgRx effects depends on how you want your effects to handle the data stream and side effects triggered by actions:

Use map when:

  • You simply need to transform each value emitted by the source Observable into a new value.
  • The order of emissions doesn’t matter.
  • There are no side effects involved.

Example: Doubling a counter value:

map((action) => action.payload * 2)

Use switchMap when:

  • You want to cancel any ongoing side effects and initiate a new one based on the latest emission.
  • The order of emissions matters, and you only care about the results from the latest action.
  • You might have multiple side effects triggered in rapid succession, but only the most recent one should be processed.

Example: Fetching user data based on the latest selected user ID:

TypeScript

switchMap((action) => this.userService.getUser(action.payload.userId))

Use exhaustMap when:

  • You want to ensure only one side effect is processed at a time, even if multiple emissions occur rapidly.
  • Any subsequent emissions from the source Observable while the inner Observable is active should be discarded.
  • This is useful for preventing unintended side effects due to rapid user input (e.g., search queries).

Example: Debouncing a search query to avoid overwhelming the server with too many requests:

exhaustMap((action) => this.productService.searchProducts(action.payload.searchTerm))

Here’s a table summarizing the key considerations:


메타데이터
post_id
c1d9ea23713b
slug
understanding-map-switchmap-and-exhaustmap-in-ngrx-effects-a-guide-to-stream-transformation-c1d9ea23713b
url
https://medium.com/@louistrinh/understanding-map-switchmap-and-exhaustmap-in-ngrx-effects-a-guide-to-stream-transformation-c1d9ea23713b
canonical_url
https://medium.com/@louistrinh/understanding-map-switchmap-and-exhaustmap-in-ngrx-effects-a-guide-to-stream-transformation-c1d9ea23713b
author_url
https://medium.com/@louistrinh
status
ok
fetched_at
2026-09-04 21:40:00