Logo

dev-resources.site

for different kinds of informations.

🚀 Learning Through Experience: A Tale of NgRx Effects

Published at
1/8/2025
Categories
angular
ngrx
redux
frontend
Author
hassantayyab
Categories
4 categories in total
angular
open
ngrx
open
redux
open
frontend
open
Author
12 person written this
hassantayyab
open
🚀 Learning Through Experience: A Tale of NgRx Effects

As developers, we’ve all faced those moments when our code doesn’t behave as expected, and we’re left scratching our heads. One such moment for me involved NgRx Effects – specifically where to place map and catchError when handling service calls.

🔍 Here’s the context:
I was working on an Angular project using NgRx, and I structured my effect like this:

loadUsers$ = createEffect(() =>
  this.actions$.pipe(
    ofType(UserActions.loadUsers),
    mergeMap(() =>
      this.userService.getUsers().pipe(
        map((users) => UserActions.loadUsersSuccess({ users }))
      )
    ),
    catchError((error) => of(UserActions.loadUsersFailure({ error })))
  )
);
Enter fullscreen mode Exit fullscreen mode

It looked perfectly fine, right? But then, something strange happened: the effect stopped processing actions entirely after an error occurred in the service call.

🤔 What went wrong?
The issue was with where I placed the catchError. By putting it in the outer pipe, the error handling wrapped the entire effect pipeline. When an error occurred, the observable terminated, effectively stopping the effect from processing any subsequent actions.


The Fix: Using a Nested Pipe

After some digging (and a few headaches), I realized the best practice is to place map and catchError inside the nested pipe for the service. Here's the corrected code:

loadUsers$ = createEffect(() =>
  this.actions$.pipe(
    ofType(UserActions.loadUsers),
    mergeMap(() =>
      this.userService.getUsers().pipe(
        map((users) => UserActions.loadUsersSuccess({ users })),
        catchError((error) => of(UserActions.loadUsersFailure({ error })))
      )
    )
  )
);
Enter fullscreen mode Exit fullscreen mode

Why This Works Better

✅ Scoped Error Handling: The catchError only handles errors from the service call (userService.getUsers()) and doesn’t interfere with the overall effect pipeline.

âś… Pipeline Continuation: The outer pipeline remains intact, ensuring the effect can continue processing future actions even if an error occurs.

âś… Clean Separation: It keeps the service logic encapsulated, making it modular and easier to maintain.


Takeaway for Developers

NgRx is powerful, but small mistakes in its implementation can lead to major issues in your application’s state management. This experience taught me:

  1. Understand the Observable Lifecycle: Misplaced operators like catchError can have unintended side effects.
  2. Follow Best Practices: Localize error handling to the service-level logic.
  3. Test Thoroughly: Always verify how your effects behave in different scenarios, especially when errors occur.

Have You Faced Similar Challenges?

If you’ve ever struggled with NgRx or faced issues like this, I’d love to hear your experiences! Let’s learn and grow together. 🚀

ngrx Article's
30 articles in total
Favicon
🚀 Learning Through Experience: A Tale of NgRx Effects
Favicon
Announcing NgRx 19: NgRx Signals Features, Action Signals, and more!
Favicon
NGRX with Angular 16
Favicon
Angular Addicts #31: The new Resource API, effect updates & more
Favicon
Simplify Your Angular Code with NgRx Entities
Favicon
ngRx Store in Angular
Favicon
Angular Addicts #29: Angular 18.2, implicit libraries, the future is standalone & more
Favicon
NgRx Use Cases, Part III: Decision-making
Favicon
Angular Addicts #28: Angular 18.1 (w. the new @let syntax), Component testing, SSR guide & more
Favicon
Angular Router URL Parameters Using NgRx Router Store
Favicon
When to Use `concatMap`, `mergeMap`, `switchMap`, and `exhaustMap` Operators in Building a CRUD with NgRx
Favicon
How to Implement ActionCreationGroup in NgRx
Favicon
A single state for Loading/Success/Error in NgRx
Favicon
How to Debug NgRx Using REDUX DevTools in Angular
Favicon
When and Why to Use REDUX NgRx in Angular
Favicon
Announcing NgRx Signals v18: State Encapsulation, Private Store Members, Enhanced Entity Management, and more!
Favicon
Angular Addicts #27: NgRx 18, New RFC: DomRef API, Web storage with Signals & more
Favicon
Announcing NgRx 18: NgRx Signals is almost stable, ESLint v9 Support, New Logo and Redesign, Workshops, and more!
Favicon
Angular Addicts #26: Angular 18, best practices, recent conference recordings & more
Favicon
How to Handle Side Effects in Angular Using NgRx Effects
Favicon
How to Use NgRx Selectors in Angular
Favicon
Angular Addicts #25: Angular and Wiz will be merged, the differences between React and Angular & more
Favicon
Angular Addicts #24: Angular 17.3, Signals and unit testing best practices, Storybook 8 & more
Favicon
Creating a ToDo App with Angular, NestJS, and NgRx in a Nx Monorepo
Favicon
Here's how NgRx selectors actually work internally
Favicon
Angular Addicts #23: Angular 17.2, Nx 18, Signal forms, Analog, WebExpo & more
Favicon
All you need to know to get started with the NgRx Signal Store
Favicon
Angular Addicts #22: Angular 17.1, Signal Inputs, State management tips & more
Favicon
11 friends of state management in Angular
Favicon
The best of Angular: a collection of my favorite resources of 2023

Featured ones: