React-redux 项目 - 链式依赖异步调用不适用于 redux-promise 中间件?
Posted
技术标签:
【中文标题】React-redux 项目 - 链式依赖异步调用不适用于 redux-promise 中间件?【英文标题】:React-redux project - chained dependent async calls not working with redux-promise middleware? 【发布时间】:2018-06-29 10:16:36 【问题描述】:我是使用 redux 的新手,我正在尝试将 redux-promise 设置为中间件。我有这种情况,我似乎无法开始工作(当我只是想在没有链接的情况下进行一个异步调用时,事情对我有用)
假设我有两个 API 调用:
1) getItem(someId) -> attr1: something, attr2: something, tagIds: [...]
2) getTags() -> [someTagObject1, someTagObject2]
我需要调用第一个,并获取一个项目,然后获取所有标签,然后返回一个包含项目和与该项目相关的标签的对象。
现在,我的动作创建者是这样的:
export function fetchTagsForItem(id = null, params = new Map())
return
type: FETCH_ITEM_INFO,
payload: getItem(...) // some axios call
.then(item => getTags() // gets all tags
.then(tags => toItemDetails(tags.data, item.data)))
我在toItemDetails中有一个console.log,我可以看到当调用完成后,我们最终进入toItemDetails并得到正确的信息。但是,看起来我们在调用完成之前就到达了减速器,而我只是从减速器获得了一个未定义的有效负载(它不会再试一次)。对于这种情况,reducer 只是试图返回 action.payload。
我知道链接调用不是很好,但我至少希望看到它工作。这是可以通过 redux-promise 完成的吗?如果没有,任何有关如何实现此功能的示例将不胜感激!
【问题讨论】:
为什么说链式调用不好?当你有一个依赖于前一个异步行为结果的异步行为时,它们是绝对必要的。 你能通过一个异步调用发布有效的版本吗? 【参考方案1】:我用占位符函数填充了你丢失的代码,它对我有用 - 我的有效负载最终包含一个承诺,它解析为返回值 toItemDetails
。所以也许它是你没有包含在代码中的东西。
function getItem(id)
return Promise.resolve(
attr1: 'hello',
data: 'data inside item',
tagIds: [1, 3, 5]
);
function getTags(tagIds)
return Promise.resolve( data: 'abc' );
function toItemDetails(tagData, itemData)
return itemDetails: tagData, itemData ;
function fetchTagsForItem(id = null)
let itemFromAxios;
return
type: 'FETCH_ITEM_INFO',
payload: getItem(id)
.then(item =>
itemFromAxios = item;
return getTags(item.tagIds);
)
.then(tags => toItemDetails(tags.data, itemFromAxios.data))
;
const action = fetchTagsForItem(1);
action.payload.then(result =>
console.log(`result: $JSON.stringify(result)`);
);
输出:
result: "itemDetails":"tagData":"abc","itemData":"data inside item"
为了在第二步中访问item
,您需要将它存储在一个在fetchTagsForItem
的函数范围内声明的变量中,因为这两个.then
本质上是兄弟姐妹:两者都可以访问封闭范围,但对 .then
的第二次调用将无法访问在第一次调用中声明的 var。
关注点分离
创建您发送到 Redux 的操作的代码也在进行多次 Axios 调用并处理返回的数据。这使得阅读和理解变得更加复杂,并且使得处理 Axios 调用中的错误等事情变得更加困难。我建议把事情分开。一种选择:
将任何调用 Axios 的代码放在自己的函数中 将payload
设置为该函数的返回值。
将该函数和所有其他调用 Axios 的函数移动到一个单独的文件(或一组文件)中。该文件将成为您的 API 客户端。
这看起来像:
// apiclient.js
const BASE_URL = 'https://yourapiserver.com/';
const makeUrl = (relativeUrl) => BASE_URL + relativeUrl;
function getItemById(id)
return axios.get(makeUrl(GET_ITEM_URL) + id);
function fetchTagsForItemWithId(id)
...
// Other client calls and helper funcs here
export default
fetchTagsForItemWithId
;
您的操作文件:
// items-actions.js
import ApiClient from './api-client';
function fetchItemTags(id)
const itemInfoPromise = ApiClient.fetchTagsForItemWithId(id);
return
type: 'FETCH_ITEM_INFO',
payload: itemInfoPromise
;
【讨论】:
如果将 toItemDetails 的第二个参数替换为 item.data 是否仍然有效?我相信在没有嵌套的情况下我很难让它工作。 (我在我的问题中打错了 - 现在已修复) 嵌套导致item
被声明在包含对then()
的第二次调用的范围内。要使其在没有嵌套的情况下工作,请将item
存储在一个变量中,该变量在包含对then()
的两个调用的范围内声明:fetchTagsForItem
函数范围。查看更新的代码。以上是关于React-redux 项目 - 链式依赖异步调用不适用于 redux-promise 中间件?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 thunk 在 react-redux 挂钩中进行异步调用?
如何使用 Combine + Swift 复制 PromiseKit 风格的链式异步流