英文:
How can I best use rxjs to perform multiple fetch operations in a single action using a forEach approach
问题
让我解释一下您需要实现的语法:
首先,您需要使用`frameworks`对象来迭代每个框架,并对每个框架执行相应的API调用。
在这种情况下,您可以使用`Object.keys`来获取`frameworks`对象中所有框架的键(即框架的名称)的数组。
然后,您可以使用`Array.prototype.map`方法来将每个框架的键映射到相应的API调用。
最后,您可以使用`forkJoin`来同时处理所有API调用,以确保在所有调用都完成后再继续。
以下是相应的代码示例:
```js
let fetchHabitatsEpic = (action$, state$) => action$.pipe(
ofType(
mapperActions.initialise.type,
),
switchMap(() => {
const frameworkKeys = Object.keys(frameworks);
const apiCalls = frameworkKeys.map(key => {
const framework = frameworks[key];
return fetchHabitats(framework).pipe(
map(result => mapperActions.fetchHabitatsCompleted(result)),
catchError(e => of(globalActions.errorOccurred(e.message)))
);
});
return concat(
of(globalActions.startLoading('habitats')),
forkJoin(apiCalls).pipe(
map(() => globalActions.stopLoading('habitats')),
catchError(e => of(globalActions.errorOccurred(e.message)))
)
);
})
);
在此示例中,frameworkKeys
是frameworks
对象中所有框架的键的数组。然后,我们使用map
方法将每个框架的键映射到相应的API调用,并将所有调用放入apiCalls
数组中。
接着,我们使用forkJoin
来同时处理所有API调用。一旦所有调用都完成,它会返回一个数组,其中包含每个API调用的结果。最后,我们在concat
中包含了开始和结束加载的动作。
这样,您就可以使用单个动作触发所有四个框架的API调用,并在所有调用完成后停止加载。
英文:
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?
答案1
得分: 1
你可以使用Object.values()
来迭代框架,然后使用Array.map()
将它们映射到API调用,如下所示:
concat(
of(globalActions.startLoading('habitats')),
...Object.values(frameworks).map(framework =>
fetchHabitats(framework).pipe(
map(result => mapperActions.fetchHabitatsCompleted(result)),
catchError(e => of(globalActions.errorOccurred(e.message)))
)
)
)
英文:
You can use Object.values()
to iterate over the frameworks and Array.map()
to map them to API calls, as follows:
concat(
of(globalActions.startLoading('habitats')),
...Object.values(frameworks).map(framework =>
fetchHabitats(framework).pipe(
map(result => mapperActions.fetchHabitatsCompleted(result)),
catchError(e => of(globalActions.errorOccurred(e.message)))
)
)
)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论