如何在Redux-Saga中调用另一个Generator函数?
在getMyCollectionDetails中为每个模板获取对应硬币详情
需求说明
我需要在getMyCollectionDetails生成器函数内,通过getTemplateCoins生成器获取active和unactive列表中每个模板ID对应的硬币详情,最终返回包含这些额外信息的新列表,再传递给getMyCollectionDetailsSuccess action。
现有代码
MyCollectionSaga
export function* getMyCollectionDetails(api) { try { const responseDetails = yield makeRequest(api, api.getMySocialProfile, null); const responseBadges = yield makeRequest(api, api.getBadges, null); const responseTemplates = yield makeRequest(api, api.getTemplates, null); if (responseDetails.ok && responseBadges.ok && responseTemplates.ok) { const templates = responseTemplates.data.results.map((e) => parseTemplate(e)); const active = templates.filter((e) => e.active); const unactive = templates.filter((e) => !e.active); // 希望在这里调用getTemplateCoins,传入active和unactive列表中每个项的id // 把结果存入新数组,再传给下方的getMyCollectionDetailsSuccess yield put( MyCollectionsActions.getMyCollectionDetailsSuccess( responseDetails.data.result, responseBadges.data.result, active, unactive ) ); } } catch (error) { log(error); } } export function* getTemplateCoins(api, { templateId }) { try { const params = { templateId }; const response = yield makeRequest(api, api.getTemplateCoins, params); if (response.ok) { const coinsCollections = response.data.results.coins.filter((e) => e.inCollection); const coinsMissing = response.data.results.coins.filter((e) => !e.inCollection); const coins = [ { title: i18n.t('common:collectionTemplateSectionCollected'), data: coinsCollections }, { title: i18n.t('common:collectionTemplateSectionMissing'), data: coinsMissing }, ]; yield put(CollectionTemplateActions.getTemplateCoinsSuccess(coins)); } else { yield put( CollectionTemplateActions.getTemplateCoinsFailure(i18n.t('common:genericErrorMessage')) ); } } catch (error) { log(error); yield put( CollectionTemplateActions.getTemplateCoinsFailure(i18n.t('common:genericErrorMessage')) ); } }
MyCollectionRedux
const getMyCollectionDetails = (state) => { return { ...state, isLoading: true, error: false, message: '' }; }; const getMyCollectionDetailsSuccess = ( state, { socialProfile, allBadges, templatesActivated, templatesUnactivated } ) => { return { ...state, socialProfile, allBadges, templatesActivated, templatesUnactivated, isLoading: false, error: false, }; }; const getMyCollectionDetailsFailure = (state, { message }) => { return { ...state, message, isLoading: false, error: true }; };
解决方案
核心思路
- 重构
getTemplateCoins:让它直接返回硬币数据,而非单独派发action,这样可以在getMyCollectionDetails中直接获取结果。 - 批量获取详情:使用Saga的
all和call方法,并行遍历active和unactive列表,为每个模板调用getTemplateCoins并合并结果。 - 传递新列表:将包含硬币详情的模板列表传递给成功action,Reducer无需额外修改(只需确保模板对象新增的
coins属性能被正常存储)。
修改后的代码
重构后的getTemplateCoins
export function* getTemplateCoins(api, templateId) { try { const params = { templateId }; const response = yield makeRequest(api, api.getTemplateCoins, params); if (response.ok) { const coinsCollections = response.data.results.coins.filter((e) => e.inCollection); const coinsMissing = response.data.results.coins.filter((e) => !e.inCollection); // 返回硬币数据,而非直接派发action return [ { title: i18n.t('common:collectionTemplateSectionCollected'), data: coinsCollections }, { title: i18n.t('common:collectionTemplateSectionMissing'), data: coinsMissing }, ]; } else { throw new Error(i18n.t('common:genericErrorMessage')); } } catch (error) { log(error); throw error; // 抛出错误让上层处理 } }
修改后的getMyCollectionDetails
export function* getMyCollectionDetails(api) { try { const responseDetails = yield makeRequest(api, api.getMySocialProfile, null); const responseBadges = yield makeRequest(api, api.getBadges, null); const responseTemplates = yield makeRequest(api, api.getTemplates, null); if (responseDetails.ok && responseBadges.ok && responseTemplates.ok) { const templates = responseTemplates.data.results.map((e) => parseTemplate(e)); const active = templates.filter((e) => e.active); const unactive = templates.filter((e) => !e.active); // 并行获取所有active模板的硬币详情,合并到模板对象中 const activeWithCoins = yield all( active.map((template) => call(getTemplateCoins, api, template.id).then((coins) => ({ ...template, coins })) ) ); // 并行获取所有unactive模板的硬币详情,合并到模板对象中 const unactiveWithCoins = yield all( unactive.map((template) => call(getTemplateCoins, api, template.id).then((coins) => ({ ...template, coins })) ) ); yield put( MyCollectionsActions.getMyCollectionDetailsSuccess( responseDetails.data.result, responseBadges.data.result, activeWithCoins, unactiveWithCoins ) ); } } catch (error) { log(error); // 可选:派发全局失败action yield put(MyCollectionsActions.getMyCollectionDetailsFailure(i18n.t('common:genericErrorMessage'))); } }
注意事项
- 如果
getTemplateCoins原本需要单独触发(比如其他场景调用),可以保留原函数,新增一个纯获取数据的版本(比如fetchTemplateCoins)来避免冲突。 - 并行请求使用
all可以提升性能,避免串行请求的等待时间。 - 错误处理可以根据需求调整,比如部分请求失败时是否继续处理其他成功的结果。
内容的提问来源于stack exchange,提问作者mistybui
相关产品推荐
相关产品推荐

