Search code examples
angularngrxngrx-component-store

NGRX component-store effect is looped by calling patchState


My effect loops infinitely, and I'm not sure why.

  interface LatestAppointmentsWidgetState {
    loading: boolean;
    page: number;
    pagedData: Paged<Appointment>;
  }

  @Injectable()
  export class LatestAppointmentsWidgetStore extends ComponentStore<LatestAppointmentsWidgetState> {

  private readonly params$ = this.select(state => ({
    page: state.page
  }));

  readonly loadBusinesses = this.effect(() => {
    return this.params$.pipe(
      tap({ next: () => this.patchState({ loading: true }) })
    );
  });
}

I've tried to only keep the relevant code. It seems that the patchState within the effect triggers the params$ selector. But from my understanding patchState should only update the state that matches the partial state passed as an argument. Does anyone know why this happens?


Solution

  • This happens because:

    1. patch state updates the state
    2. the selector "reacts" the new state
    3. the selector creates a new instance
    4. because of the new instance the effect is retriggered

    In order to prevent this consider just returning the boolean value.

      private readonly page$ = this.select(state => state.page);
    
      // you can use it to recreate params$
      private readonly params$ = this.select(this.page$, page => ({page});
    

    A second option is to make the effect "smarter" and ignore re-emits, e.g. by using distinct(By).