使用 Promis.all 处理多个 api 调用并使用 react-redux 处理数据

Handling multiple api calls with Promis.all and manipulating the data with react-redux

我正在构建一个带有 react/redux 的应用程序,用于管理 Collection 电子设备(=捐赠)。 在第一阶段,我需要进行 2 次 api 调用: 第一个和第二个是捐赠数据和捐赠者数据(在mongodb中保持不同collections),然后将它们合并。此信息显示在捐赠路线中。 动作看起来像这样:

const basicUrl = 'http://localhost:8000/api';
export const requestDonor_DonationData = () => getDonationData (
    `${basicUrl}/donor`, 
    `${basicUrl}/donation`
);

getDonationData 函数如下所示:

import {
    REQUEST_ENTITIES_PENDING,
    REQUEST_ENTITIES_SUCCES,
    REQUEST_ENTITIES_FAILED
} from './constants';
 

export const getDonationData = (urlDonor, urlDonation) => (dispatch) => {
    dispatch ( {type: REQUEST_ENTITIES_PENDING} );
    Promise.all([
        fetch(urlDonor).then(res => res.json()),
        fetch(urlDonation).then(res => res.json())
     ]).then ( ([ donorResult, donationResult]) => donorResult.data.map( (e, i) =>  Object.assign(e, donationResult.data[i]) ) )
        .then( mergedData => dispatch({type: REQUEST_ENTITIES_SUCCES, payload: mergedData }) )
        .catch(error => dispatch({type: REQUEST_ENTITIES_FAILED, payload: error}) ) 
}

效果不错。

在第二阶段,当一个捐赠被偷看后,它变成了一个设备(不是完美的词..),这意味着现在它正在等待检查。此信息显示在设备路线中。 设备数据包含 donationId 和状态(不同于捐赠状态)。 现在我想做类似的事情:

  1. 拨打 3 api 次电话(获取捐赠者、捐赠和设备数据)

  2. 合并捐赠者及其捐赠数据

  3. 过滤合并 已查看的捐赠数据 (status='DONE')

  4. 创建一个新的 json,它采用合并的数据并替换 ID 和 捐赠状态与设备的 ID 和状态。

我试过了 使用第一种方法(仅使用 Promise.all)来做到这一点,但发现 使用多个“.then”非常令人困惑...

这是我尝试过的: 行动-

export const requestEquipmentData = () => getEquipmentData ( 
    [
    `${basicUrl}/donor`, 
    `${basicUrl}/donation`,
    `${basicUrl}/equipment`
    ]
);

export const getEquipmentData = (urls) => (dispatch) => {
    dispatch ( {type: REQUEST_ENTITIES_PENDING} );
    try {
        const [ donorResult, donationResult, equipmentResult ] =  Promise.all(urls.map(async function(url) {
            const response = await fetch(url);
            return response.json();
        }));
        const donationInfo =  donorResult.data.map( (e, i) => Object.assign(e, donationResult.data[i]) );
        const filteredDonation = donationInfo.filter(item =>item.status==='DONE');
        const equipment =  filteredDonation.map( (donation,i) => {
                let obj = donation;
                obj.id = equipmentResult.data[i].id;
                obj.status = equipmentResult.data[i].status;   
                return obj;
        })
        dispatch({type: REQUEST_ENTITIES_SUCCES, payload: equipment });

    }  catch (error) {
        dispatch({type: REQUEST_ENTITIES_FAILED, payload: error})
    }
}

但是我做错了,那就是错误:

type: "REQUEST_ENTITIES_FAILED", payload: TypeError: undefined is not a function

如有任何帮助,我将不胜感激

Promise.all() 的结果是 Promise,解析为 array 结果。它本身不是一个数组,所以你不能像这样解构它。

您可以使用与第一个示例相同的 .then() 方法:

export const getEquipmentData = (urls) => (dispatch) => {
    dispatch({ type: REQUEST_ENTITIES_PENDING });
    Promise.all(urls.map(async function (url) {
        const response = await fetch(url);
        return response.json();
    })).then(([donorResult, donationResult, equipmentResult]) => {
        const donationInfo = donorResult.data.map((e, i) => Object.assign(e, donationResult.data[i]));
        const filteredDonation = donationInfo.filter(item => item.status === 'DONE');
        const equipment = filteredDonation.map((donation, i) => {
            let obj = donation;
            obj.id = equipmentResult.data[i].id;
            obj.status = equipmentResult.data[i].status;
            return obj;
        })
        dispatch({ type: REQUEST_ENTITIES_SUCCES, payload: equipment });
    }).catch(error) {
        dispatch({ type: REQUEST_ENTITIES_FAILED, payload: error })
    }
}

或者您可以使用 async/await 语法。 有关解决 Promise 数组的一般性讨论。

export const getEquipmentData = (urls) => async (dispatch) => {
    dispatch ( {type: REQUEST_ENTITIES_PENDING} );
    try {
        const [ donorResult, donationResult, equipmentResult ] =  await Promise.all(urls.map(async function(url) {
            const response = await fetch(url);
            return response.json();
        }));
        const donationInfo =  donorResult.data.map( (e, i) => Object.assign(e, donationResult.data[i]) );
        const filteredDonation = donationInfo.filter(item =>item.status==='DONE');
        const equipment =  filteredDonation.map( (donation,i) => {
                let obj = donation;
                obj.id = equipmentResult.data[i].id;
                obj.status = equipmentResult.data[i].status;   
                return obj;
        })
        dispatch({type: REQUEST_ENTITIES_SUCCES, payload: equipment });

    }  catch (error) {
        dispatch({type: REQUEST_ENTITIES_FAILED, payload: error})
    }
}

在我看来,您在这里的一般方法并不好。您应该阅读 Normalizing State Shape 上的指南。您的 API 似乎正在返回规范化数据,然后您通过组合来自多个端点的数据对其进行“非规范化”。