Search code examples
angularobservablestoreinfinite-loopngrx

Subscribe stuck in endless loop when state changed


Does someone know how to fix an endless loop when dispatching an action to the store inside a store subscription? To avoid the loop I had to add a condition inside the store, but I wonder whether there is a more elegant way to make it work.

Code with endless loop:

ngOnInit(): void {
    this.store.select('admin').subscribe(
      (adminState: AdminState) => {
          const relations = 'dockSubscriptions,dockSubscription.dock,dock.tiles';
          const uri = `users/${adminState.currentUserId}?relations=${relations}`;
          this.apiService.get(uri).subscribe(
            (user: User) => {
              this.store.dispatch(new AppActions.SetCurrentUser(user));
              this.router.navigate(['/']);
              this.currentUserId = adminState.currentUserId;
            },
            (error) => {
              this.auth.logout();
            }
          );
        }
    );
  }

Code without loop:

ngOnInit(): void {
    this.store.select('admin').subscribe(
      (adminState: AdminState) => {
        if (adminState.currentUserId && adminState.currentUserId !== this.currentUserId) {
          const relations = 'dockSubscriptions,dockSubscription.dock,dock.tiles';
          const uri = `users/${adminState.currentUserId}?relations=${relations}`;
          this.apiService.get(uri).subscribe(
            (user: User) => {
              this.store.dispatch(new AppActions.SetCurrentUser(user));
              this.router.navigate(['/']);
              this.currentUserId = adminState.currentUserId;
            },
            (error) => {
              this.auth.logout();
            }
          );
        }
      }
    );
  }

Any better solutions?


Solution

  • Use the filter operator from rxjs.

    this.store.select('admin').pipe(filter(state => { return state.currentUserId && state.currentUserId !== this.currentUserId })).subscribe(...)

    Or, it seems like you don't really need an open subscription to the user state, so you can just pipe a take(1).