I have an application with 2 menu item; Teams, Players. Whenever I toggle between them, I have to unnecessary api call even though I have the data in store.
Below is the effects file: //auth.effects.ts
loadTeams$ = createEffect(() => {
return this.actions$.pipe(
ofType(AuthActions.loadTeams),
switchMap((action) =>
this.apiService.teams$.pipe(
tap(() => console.log('get teams request')),
map((teams: Team[]) => AuthActions.loadTeamsSuccess({ teams })),
catchError((error) => {
console.log('err', error);
return of(AuthActions.loadFailure({ error }));
})
)
)
);
});
Below is the component from which I make api call
teams-list.component.ts
export class TeamsListComponent implements OnInit {
loading$?: Observable<boolean>;
error$?: Observable<string>;
teams$?: Observable<Team[]>;
retrySubject$ = new BehaviorSubject<boolean>(true);
constructor(private store: Store<State>) {}
ngOnInit(): void {
this.store.dispatch(loadTeams());
this.teams$ = this.store.select(getTeams);
this.error$ = this.store.select(getError);
this.loading$ = this.store.select(getLoading);
}
fetchRetry() {
this.retrySubject$.next(false);
}
}
This line in ngOnInit cause unnecessary api call. this.teams$ = this.store.select(getTeams);
How can I prevent it so that it makes the api call one time when initializing the app?
CodePudding user response:
loadTeams$ = createEffect(() => {
return this.actions$.pipe(
ofType(AuthActions.loadTeams),
// read the actions$ for an load success event
withLatestFrom(this.actions$.pipe(ofType(AuthActions.loadTeamsSuccess)),
// no success event? no teams loaded, so go on
filter(([loadTeamsAction, loadTeamsSuccessAction]) => !loadTeamsSuccessAction),
// remove unnecessary action
map(([loadTeams,]) => loadTeams),
switchMap((action) =>
this.apiService.teams$.pipe(
tap(() => console.log('get teams request')),
map((teams: Team[]) => AuthActions.loadTeamsSuccess({ teams })),
catchError((error) => {
console.log('err', error);
return of(AuthActions.loadFailure({ error }));
})
)
)
);
});
CodePudding user response:
Read the store after receiving the event, then filter out emits that already have a value in the store.
detail = createEffect(() => {
return this.actions.pipe(
ofType(ProductDetailPage.loaded),
concatLatestFrom(() => this.store.select(selectProducts)),
filter(([{ payload }, products]) => !!products[payload.sku]),
mergeMap(([{payload}]) => {
...
})
)
})