I am new to React and tasked with modifying an existing application which already performs multiple api calls. The pattern that is in use in the app is demonstrated by the below example. EG if an action mapperActions.selectPolygon of type CaseReducerActions<CaseReducers> is raised, then the below code will execute, calling the fetchPolygon function to retrieve data asynchronously from an AWS lambda and the returned result will be processed by the fetchPolygonCompleted function.
let fetchPolygonStatsEpic = (action$: any, state$: StateObservable<RootState>) => action$.pipe(
ofType(
mapperActions.selectPolygon.type,
mapperActions.alterQueryIndexname.type,
),
filter(() => state$.value.mapper.selectedPolygon !== undefined),
switchMap(() =>
concat(
of(globalActions.startLoading('polygon')),
fetchPolygon(state$.value.mapper).pipe(
map(result => mapperActions.fetchPolygonCompleted(result)),
catchError(e => of(globalActions.errorOccurred(e.message)))),
of(globalActions.stopLoading('polygon')),
)
)
)
The change I need to implement is as follows:
I have a type 'Framework'...
export type Framework = {
....
}
...a collection of these...
export const frameworks: {[framework: string]: Framework} = {
liveng0: {
...
},
liveng1: {
...
},
habmosCairngorms: {
...
},
spaceintCairngorms: {
...
}
}
..and an API method that retrieves data for a specified Framework...
export let fetchHabitats = (requiredFramework: Framework): Observable<FrameworkHabitats> => {
...
}
When the action mapperActions.initialise of type CaseReducerActions<CaseReducers> is raised, I need to execute a block of code which will execute and process 4 separate asynchronous API calls to fetch the data for each of the 4 framework types above in turn.
A naive approach of simply copy-and-pasting the API call for each framework in turn within the app's establised pattern for fetching data actually works correctly and produces the results I require, ie:
let fetchHabitatsEpic = (action$: any, state$: StateObservable<RootState>) => action$.pipe(
ofType(
mapperActions.initialise.type,
),
switchMap(() =>
concat(
of(globalActions.startLoading('habitats')),
fetchHabitats(frameworks.liveng0).pipe(
map(result => mapperActions.fetchHabitatsCompleted(result)),
catchError(e => of(globalActions.errorOccurred(e.message)))),
fetchHabitats(frameworks.liveng1).pipe(
map(result => mapperActions.fetchHabitatsCompleted(result)),
catchError(e => of(globalActions.errorOccurred(e.message)))),
fetchHabitats(frameworks.habmosCairngorms).pipe(
map(result => mapperActions.fetchHabitatsCompleted(result)),
catchError(e => of(globalActions.errorOccurred(e.message)))),
fetchHabitats(frameworks.spaceintCairngorms).pipe(
map(result => mapperActions.fetchHabitatsCompleted(result)),
catchError(e => of(globalActions.errorOccurred(e.message)))),
of(globalActions.stopLoading('habitats')),
)
)
)
Although the above works as required, it clearly needs to be replaced with a forEach approach that operates over each Framework in turn and treats each API call atomically, whilst still being able to trigger all 4 from a single action. Could you please explain the syntax required to achieve this?