在 React Redux 中调度操作之前等待多个 Axios 调用
Posted
技术标签:
【中文标题】在 React Redux 中调度操作之前等待多个 Axios 调用【英文标题】:Awaiting Multiple Axios Calls before Dispatching Action in React Redux 【发布时间】:2019-12-29 04:51:40 【问题描述】:我有一个 React Redux 应用程序需要使用 axios
调用多个 API 端点,等待这些 API 调用的结果,然后分派一个操作。
问题:在下面我当前的实现中,在axios
返回 API 调用结果之前,redux-thunk
似乎正在调度该操作。
我们如何解决这个问题,以便在调度操作之前等待 3 个 axios
调用返回所有 3 个结果?
/src/actions/index.js
const axios = require('axios');
import GET_PRICES from './types';
export function getSpotPrice(crypto)
axios.get(`https://api.coinbase.com/v2/prices/$crypto-USD/spot`).then( (response) =>
return parseFloat(response.data.data.amount);
).catch((err) =>
console.log(err)
)
function timeout(ms)
return new Promise(resolve => setTimeout(resolve, ms));
export function getSpotPrices()
return function(dispatch)
const cryptoList = ['BTC', 'ETH', 'XRP'];
let cryptoRates =
cryptoList.forEach(async (crypto, i) =>
await timeout(1000); // Wait 1 sec between API calls
cryptoRates[crypto] = await getSpotPrice(crypto);
);
dispatch(
type: GET_PRICES,
payload: cryptoRates,
)
console.log('cryptoRates:', cryptoRates) // returns
【问题讨论】:
作用域/异步行为在可枚举的回调中变得有点奇怪。试着把它变成一个for..of
循环而不是forEach
并行提取有效还是需要连续提取?
@Dom 连续,避免敲击 API 端点。
【参考方案1】:
您需要在调度之前使包含函数异步等待所有异步调用,如下所示:
export function getSpotPrices()
return async function(dispatch)
const cryptoList = ['BTC', 'ETH', 'XRP'];
let cryptoRates =
for(let crypto of cryptoList)
await timeout(1000); // Wait 1 sec between API calls
cryptoRates[crypto] = await getSpotPrice(crypto);
dispatch(
type: GET_PRICES,
payload: cryptoRates,
);
console.log('cryptoRates:', cryptoRates);
【讨论】:
我知道你打算这样做,但有一些事情是关闭的,这也略微改变了 OP 的预期行为。如果你想映射 Promise,你必须在map
中使用 return getSpotPrice(crypto)
。你不想解决里面的承诺。 Promise.all
将并行调用每个 api 调用,并且不会等待他的 1 秒间隔
没错。相应地更新了答案。
虽然上述方法适用于最佳情况,但您应该始终将 async
调用包装在 try/catch
块中。否则,如果 AJAX 调用失败,它可能会破坏整个应用程序。工作代码框:codesandbox.io/s/redux-thunk-multi-api-calls-ul5h4?fontsize=14
@MattCarlotta - 您不需要将每个 await
都包含在 try/catch
中 - 只是您真正想要捕获的那些。 OP 可能是 try/catch
ing dispatch(getSpotPrices())
@Nyxynyx 没有它,您将在重新挂载时显示旧数据(注释掉上面提到的调度,转到“货币”,然后转到“主页”,然后返回“货币”) - - 它会在 3+ 秒后用新数据更新 DOM。除非用户全神贯注地盯着数据并且他们等待 3 秒以上,否则这可能会让他们误以为它只在第一次装载期间获取货币一次。上面的调度在重新挂载时重置回初始状态,导致<Spinner />
在再次获取数据之前显示——让用户更清楚地知道数据正在更新。【参考方案2】:
我相信您可以做到这一点的另一种方法是使用 Promise.all 方法。当数组中的所有 promise 都已解决时,就会调用 then 语句。
var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject)
setTimeout(resolve, 100, 'foo');
);
Promise.all([promise1, promise2, promise3]).then(function(values)
console.log(values);
);
【讨论】:
以上是关于在 React Redux 中调度操作之前等待多个 Axios 调用的主要内容,如果未能解决你的问题,请参考以下文章
React/Redux - 在应用程序加载/初始化时调度操作