How to wait for dispatch to be completed before selecting from a store. Ngrx related issue
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
Sian20R
Updated on June 05, 2022Comments
-
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 about 5 yearsHi, 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 about 5 yearsYea 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 over 2 years
Store.dispatch
returnsvoid
, you can't subscribe to it. -
Experimenter over 2 yearsGood solution but in my case .release() function doesn't work. Not sure why... maybe something wrong on NgRx side, using 11.1.1 version.