How to wait for dispatch to be completed before selecting from a store. Ngrx related issue

12,348

Solution 1

You can't, a dispatch is a fire and forget that you can't wait on.

Luckily this isn't needed because this.store.select('teams') is an observable. This means that if it changes, the observable will be emitted a new value and this will cause your component to re-render.

If the list stays empty, you can check if your state is in fact updated this can be done with @ngrx/store-devtools. If the state is updated but it doesn't show in the component, make sure you don't modify the state directly, but that you're creating a new reference to the array.

Solution 2

What you can do is to clear the selector just before dispatch and filter the response :

fromApp.GetStuff.release();
// the state is now empty
this.store.dispatch(fromApp.FetchMyStuff);
// any previous value has been forgotten. The next defined value is just what you want
this.stuff = this.store.select(fromApp.GetStuff).pipe(
    filter(stuff => !!stuff)
);

See https://ngrx.io/guide/store/selectors#resetting-memoized-selectors

Share:
12,348
Sian20R
Author by

Sian20R

Updated on June 05, 2022

Comments

  • Sian20R
    Sian20R almost 2 years

    How can I wait for a dispatch to be completed before I select from a store. Do not have any luck in Googling? In this case, how do I wait for the dispatch to be done first before selecting from store?

    My codes, appreciate the help supported.

    **team-list.component.ts**
    
     teamsState: Observable<{teams: Team[]}>;
    
      constructor(private store: Store<fromApp.AppState>) { }
    
      ngOnInit() {
        this.store.dispatch(new TeamActions.GetTeams({
          search: this.search,
          limit: this.limit,
          skip: this.skip,
          sortBy: this.sortBy
        }));
        this.teamsState = this.store.select('teams');
      }
    
    **team-list.component.html**
    
    <mat-expansion-panel
        *ngFor="let team of (teamsState | async).teams; let i = index">
        <mat-expansion-panel-header>
          <div class="container-fluid">
            <div class="row">
              <div class="col-md-1">{‌{ i+1 }}</div>
              <div class="col-md-1">
                  <div class="post-image">
                    <img [src]="imageUrl+team.imagePath" [alt]="team.name" style>
                  </div>
              </div>
              <div class="col-md-10"> {‌{ team.name }} </div>
            </div>
          </div>
        </mat-expansion-panel-header>
    
    effects
    @Effect() // If you do not want to dispatch any actions, if need to modify store state then remove
        teamList = this.actions$.pipe(
            ofType(TeamActions.GET_TEAMS),
                map((action: TeamActions.GetTeams) => {
                  return action.payload;
                }),
                switchMap((params: {search: string, limit: number, skip: number, sortBy: string}) => {
                    return this.httpClient.get<Team[]>(
                      `${BACKEND_URL}?search=${params.search}&&limit=${params.limit}&&skip=${params.skip}&&sortBy=${params.sortBy}`);
                }),
                map((teams: Team[]) => {
                    return {
                        type: TeamActions.SET_TEAMS,
                        payload: teams
                    };
                }),
                catchError((err, caught) => {
                  // console.log(err.error.errors);
                  this.snackBarService.showSnackBar('Unable to Get Teams', true);
                  return caught;
                })
            );
    

    Currently during first load, the dispatching action is not completed yet and when i select item from store. It is currently empty.

  • Sian20R
    Sian20R about 5 years
    Hi, Currently when I first load the page, the list is empty as it does not set any state in the store yet but I need to refresh then the items will be in the store. effects
  • timdeschryver
    timdeschryver about 5 years
    Yea the items will be automatically updated on the page when you set your state. If you first want to load the items and then make the page visible, take a look at guards -ultimatecourses.com/blog/preloading-ngrx-store-route-guards
  • Xartrick
    Xartrick over 2 years
    Store.dispatch returns void, you can't subscribe to it.
  • Experimenter
    Experimenter over 2 years
    Good solution but in my case .release() function doesn't work. Not sure why... maybe something wrong on NgRx side, using 11.1.1 version.