在 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/catching 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 - 在应用程序加载/初始化时调度操作

Redux-thunk 调度一个动作并等待重新渲染

动作调度不更新 Redux/React 中的状态

Redux thunk 在下一个操作之前没有解析 + then 不是函数或调度未定义

React 和 Redux:在一个函数中调度所有操作

使用 Redux 在 React 中调度操作的问题