DEV Community

Piotr Sobuś
Piotr Sobuś

Posted on • Edited on

1

NGRX: Notify after action has been dispatched

While working with ngrx, sometimes we need to be notified after an action has been dispatched successfully in order to perform some kind of action (e.g: open or close a modal from a component).

One of the solution would be creating a Subject in the facade class and emit a value in the effect after the success action has been dispatched:

export class UserFacade {
  readonly userAdded$: Subject<boolean> = new Subject<boolean>();

  constructor(private readonly store: Store) {}

  addUser(user: UserPayload): void {
    this.store.dispatch(addUser({ user }));
  }
}
Enter fullscreen mode Exit fullscreen mode

Our effect would look like this:

@Injectable()
export class UserEffects {
  addUser$ = createEffect(() =>
    this.actions$.pipe(
      ofType(addUser),
      switchMap(({ payload }) =>
        this.userDataService.addUser(payload).pipe(
          map(() => addUserSucceeded()),
          tap(() => this.userFacade.userAdded$.next(true)),
          catchError((error) => of(addUserFailed(error)))
        )
      )
    )
  );

  constructor(
    private readonly actions$: Actions,
    private readonly userFacade: UserFacade,
    private readonly userDataService: UserDataService
  ) {}
}
Enter fullscreen mode Exit fullscreen mode

This solution is almost ideal. We don't need to directly subscribe to the effect and we can expose the information if action has been dispatched using facade pattern. On other hand, we have to create a Subject in the facade and control it in the effect. Instead, we can utilize an injectable service that provides an observable stream of all actions and listen on the success action:

export class UserFacade {
  readonly userAdded$: Observable<boolean> = this.actions$.pipe(
    ofType(addUserSucceeded),
    mapTo(true)
  );
}
Enter fullscreen mode Exit fullscreen mode

With this solution, we don't have to create additional class member and emit anything in the effect. Now, we can use it in our component:

@UntilDestroy()
@Component({ ... })
export class UserComponent {
  constructor(
    private readonly userFacade: UserFacade,
    private readonly matDialogRef: MatDialogRef<UserComponent>
  ) {}

  confirmClicked(): void {
    this.userFacade.addUser({ ... })

    this.userFacade.userAdded$
      .pipe(
        filter((added) => added),
        take(1),
        untilDestroyed(this)
      )
      .subscribe(() => this.matDialogRef.close());
  }
}
Enter fullscreen mode Exit fullscreen mode

If you have any questions, feel free to ask them in the comments!

Top comments (0)

👋 Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay