I'm learning how to integrate the Redux architecture into an Angular app using the NGRX library and ran into an interesting issue that I was wondering about. I was wondering how I can prevent multiple and redundant API calls to the server when multiple components fire off the LoadApps action simultaneously.
I have the following reducer and effect:
export function appsReducer(state = initialState, action: AppsActions): AppsState {
switch (action.type) {
case AppsActionTypes.LoadApps:
return {
...state,
pending: true,
data: []
};
case AppsActionTypes.LoadAppsSuccess:
return {
...state,
pending: false,
data: action.payload
};
default:
return state;
}
}
@Effect()
loadApps = this.actions.pipe(
ofType(AppsActionTypes.LoadApps),
concatMap(() => this.appService.getApps().pipe(
switchMap((res: App[]) => {
return [new LoadAppsSuccess(res)];
})
))
);
that loads a list of app objects from my API. If I have two sibling components in my angular app, for example a side-bar navigation, and a top-bar navigation component that each need the list of apps, they will both fire off the LoadApps action in their OnInit methods, resulting in two of the exact same API call to the server.
Should the effect get the pending boolean from state to make sure it isn't true before firing off another api request, it seems to me the second call to the effect could have already started running before pending gets set to true.
Does NGRX provide some sort of mechanism for this?
Try using exhaustMap
.
@Effect()
loadApps = this.actions.pipe(
ofType(AppsActionTypes.LoadApps),
exhaustMap(() => this.appService.getApps()),
map(res => [new LoadAppsSuccess(res)])
);
exhaustMap
will ignore any incoming events until the observable in the exhaustMap has completed. https://www.learnrxjs.io/operators/transformation/exhaustmap.html