使用多个API调用创建Redux Observable Epic-将第一个调用的结果传递到第二个调用



这不是第一次问这样的问题,但由于某种原因,我很难理解Observables和RxJs,所以我想要求澄清一下。

我正试图写一部史诗,它将做以下事情:

  1. 接收字符串
  2. 基于该字符串进行API调用
  3. 根据第一个调用的结果再进行三个(独立的(API调用,并将它们写入状态

我读过关于concatMapforkJoin的文章,它们似乎很有用,因为concatMap应该允许我连续执行多个操作,而forkJoin是因为它可以用于将最后3个API调用的结果作为单个数组返回。

这里有一些代码,可以尝试给出我想要的东西。对于重复的问题我深表歉意,但如果能得到答案,我将不胜感激。

export const apiFetchEpic = (
action$: any,
state$: any,
{ apiClient }: IDependencies,
) =>
action$.pipe(
ofType(API_FETCH),
debounce(() => timer(300)),
withLatestFrom(state$),
mergeMap(
([
{
payload: { config, uri },
},
]: [{ payload: IApiFetchActionProps }, any]) => {
return from(apiClient.get(uri, config)).pipe(
mergeMap(res =>
of(
apiSetAction(res), // <-- I need the results of this to be passed into the next calls
apiCompleteAction({ uri }),
),
),
catchError(error =>
of(apiCompleteAction({ uri }), apiErrorAction(error)),
),
)
},
),
)

我这样解决了它:

import { ofType, combineEpics } from 'redux-observable'
import {
mergeMap,
withLatestFrom,
catchError,
debounce,
switchMap,
} from 'rxjs/operators'
import { from, of, timer, forkJoin } from 'rxjs'
import { IDependencies } from '../../configure-store'
import { apiErrorAction } from '../../reducers/errors/actions'
import {
TOC_FETCH,
tocSetAction,
ITocFetchActionProps,
tocCompleteAction,
} from '../../reducers/table-of-contents/actions'
import { defaults } from 'lodash'
// Can probably use forkJoin here, and create multiple API calls as a parallel observable
// https://github.com/patricktran/react-redux-observable-epic-forkjoin-apis/blob/master/src/epics/index.js
export const tocFetchEpic = (
action$: any,
state$: any,
{ apiClient }: IDependencies,
) => {
return action$.pipe(
ofType(TOC_FETCH),
debounce(() => timer(300)), // anti-DDoS
withLatestFrom(state$),
mergeMap(
([
{
payload: { instance },
},
]: [{ payload: ITocFetchActionProps }, any]) => {
const params = { 'myParam': instance, limit: 1 }
return from(apiClient.get('endpoint', { params })).pipe(
mergeMap(
(result): any => {
const def = {
limit: -1,
'newParam': result.data.results[0],
}
const configurations = [
{
uri: 'endpointOne',
config: defaults({}, def),
},
{
uri: 'endpointTwo',
config: defaults(
{
'specialParam': 'table',
'specialParamTwo': 'http://example.com',
'iso2:lang': 'en',
},
def,
),
},
{
uri: 'endpointThree',
config: defaults(
{
'anotherSpecialParam': 'role',
},
def,
),
}, 
]
// Create a bunch of observables
const parallelObservables = configurations.map(api =>
from(
apiClient.get(api.uri, { params: api.config }),
).pipe(
switchMap(response => of(response)),
catchError(err =>
of(apiErrorAction(err), tocCompleteAction({ instance })),
),
),
)
// Return a forkJoin of them.
return forkJoin(
parallelObservables,
(names: any, schoolNames: any, storeNames: any) => {
//projection
return { // <- The object returned here is ultimately what gets written into state
instance: result.data.results[0],
tables: names.data.results,
labels: [
...schoolNames.data.results,
...storeNames.data.results,
],
}
},
).pipe(
switchMap(response => {
return of(
tocSetAction(response),
tocCompleteAction({ instance }),
)
}),
)
},
),
catchError(error =>
of(tocCompleteAction({ instance }), apiErrorAction(error)),
),
)
},
),
)
}
export default combineEpics(tocFetchEpic)

最新更新