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

3

14

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.

Lobell answered 26/3, 2019 at 9:52 Comment(0)
A
15

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.

Albumenize answered 26/3, 2019 at 11:4 Comment(2)
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. effectsLobell
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-guardsAlbumenize
P
1

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

Polacca answered 28/8, 2020 at 15:19 Comment(1)
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.Audient
U
-6

See if the below works for you.

this.store.dispatch(new TeamActions.GetTeams({
      search: this.search,
      limit: this.limit,
      skip: this.skip,
      sortBy: this.sortBy
    }))
    .subscribe(() => {
        this.teamsState = this.store.select('teams');
    });

The above is per ngxs state management framework. More @ https://www.ngxs.io/advanced/actions-life-cycle#asynchronous-actions

Unlash answered 29/7, 2020 at 9:28 Comment(2)
Store.dispatch returns void, you can't subscribe to it.Allotropy
The question was about ngrx. The link points to ngxs. Not the same tool.Leontina

© 2022 - 2024 — McMap. All rights reserved.