我正在与redux-observable
挣扎,试图弄清楚如何使用此流程创建史诗:
GET_ITEMS_REQUEST
行动GET_ITEM_DETAILS_REQUEST
操作,该操作将发送另一个HTTP请求以获取这些项目的更多详细信息GET_ITEMS_SUCCESS
操作,这将更新redux状态从第3步到第4步是我被困的地方。我知道如何使用商品ID发送GET_ITEM_DETAILS_REQUEST
,但我不知道如何倾听/订阅GET_ITEM_DETAILS_REQUEST
操作以获取商品详情回复。
到目前为止,我有以下内容:
function getItemsEpic(action$) {
return action$
// step 1
.ofType('GET_ITEMS_REQUEST')
.mergeMap(() => {
// step 2
return Observable.from(Api.getItems())
})
.mergeMap((items) => {
// step 3
const itemIds = items.map((item) => item.id);
return Observable.of({
type: 'GET_ITEM_DETAILS_REQUEST',
ids: itemIds
});
})
// ... what now?
.catch(() => {
return Observable.of({
type: 'GET_ITEMS_FAILURE'
});
});
}
答案 0 :(得分:1)
一种方法是,在收到这些项目后,开始收听GET_ITEM_DETAILS_FULFILLED
,然后立即使用GET_ITEM_DETAILS_REQUEST
启动startWith()
。另一部史诗会查看细节并发出GET_ITEM_DETAILS_FULFILLED
,我们的另一部史诗会耐心等待,然后将两部(物品+细节)压缩在一起。
const getItemDetailsEpic = action$ =>
action$
.ofType('GET_ITEM_DETAILS_REQUEST')
.mergeMap(({ ids }) =>
Observable.from(Api.getItemDetails(ids))
.map(details => ({
type: 'GET_ITEM_DETAILS_FULFILLED',
details
}))
);
const getItemsEpic = action$ =>
action$
.ofType('GET_ITEMS_REQUEST')
.mergeMap(() =>
Observable.from(Api.getItems())
.mergeMap(items =>
action$.ofType('GET_ITEM_DETAILS_FULFILLED')
.take(1) // don't listen forever! IMPORTANT!
.map(({ details }) => ({
type: 'GET_ITEMS_SUCCESS',
items: items.map((item, i) => ({
...item,
detail: details[i]
// or the more "safe" `details.find(detail => detail.id === item.id)`
// if your data structure allows. Might not be necessary if the
// order is guaranteed to be the same
}))
}))
.startWith({
type: 'GET_ITEM_DETAILS_REQUEST',
ids: items.map(item => item.id)
})
)
);
另外,我注意到你将catch()
放在外部的Observable链上。这可能不会完全符合您的要求。当错误到达顶部链时,你的整个史诗都将被终止 - 它将不再是将来的GET_ITEMS_REQUEST
!这是一个非常重要的区别,我们经常称它为“隔离你的Observable链”#34;。你不希望错误进一步传播。
// GOOD
const somethingEpic = action$ =>
action$.ofType('SOMETHING')
.mergeMap(() =>
somethingThatMayFail()
.catch(e => Observable.of({
type: 'STUFF_BROKE_YO',
payload: e,
error: true
}))
);
// NOT THE SAME THING!
const somethingEpic = action$ =>
action$.ofType('SOMETHING')
.mergeMap(() =>
somethingThatMayFail()
)
.catch(e => Observable.of({
type: 'STUFF_BROKE_YO',
payload: e,
error: true
}));
你有时确实希望在外链上捕获,但这通常只是针对无法恢复的错误。