承诺返回意外结果

时间:2020-06-05 17:12:47

标签: javascript reactjs promise

我对诺言和使用状态很陌生,但是我已经看了好几个小时了,我无法理解这里的问题,但这可能是我对诺言的理解。任何帮助将不胜感激。

我有一个与响应API的道具水合的成分:

const [trafficData, setTrafficData] = useState();

getTrafficDetails().then(r => {
    setTrafficData(r);
})

<TrafficWidget incomingData={trafficData} />

交通小部件组件

const TrafficWidgetComponent = (data) => {
    let [trafficDetails, setTrafficDetails] = useState(null);

    if(data){
      const toShow = data.map((item) => {
        //return some jsx
        return(<div>{item.roadName}: {item.trafficCondition}</div>)
      })

      setTrafficDetails(toShow);
    }

    return(<>{toShow}</>)
}

我的应用程序消耗的promise中返回的api的方法在这里:

const getTrafficDetails = (linkOne, linkTwo) => {
  const a = fetch(linkOne)
    .then((data) => data.json())
    .then((data) => data.TRAFFIC_INFO);
  const b = fetch(linkTwo)
    .then((data) => data.json())
    .then((data) => data.TRAFFIC_INFO);
  return Promise.all([a, b]).then((td) => {
    const copiedData = [...td]
    //do something with copiedData to combine all objects into array of objects and add new properties
    return combineAndAddMetadata(copiedData)
  });
};

combineAndAddMetadata

const combineAndAddMetadata = (trafficData) => {
  const combinedTrafficObject = [].concat(...trafficData);
  const toReturn = [];

  combinedTrafficObject.map((trafficDataItem) => {
    const { id, cotwoEmissions, utl } = trafficDataItem;

    const filteredObject = toReturn.find((item) => item.id === id);

    if (!filteredObject) {
      trafficDataItem.totalEmission = currencyFormatter(cotwoEmissions * utl);
      toReturn.push(trafficDataItem);
    } else {

      const totalCSL = cotwoEmissions * filteredObject.utl;

      filteredObject.utl += utl;
      filteredObject.totalEmission = totalCSL;
      filteredObject.totalEmissionFormatted = currencyFormatter(totalCSL);
    }
  });

此方法返回的数据是对象数组:[{...}, {...}, etc],我可以在控制台中看到它。

我无法理解的是,为什么即使我复制了回调,来自td中.then上的getTrafficDetails上的变量现在仍使用新的元数据进行了更新。

即使很奇怪,当我检查通过此方法进入TrafficWidget组件中的数据时,它也会转换为一个对象,其中包含所请求的数据,其长度为0,形式为{{1} },如果我随后通过{data: [{},{}]}在TrafficWidget组件中访问,则会导致无限循环,从而导致崩溃。 (尽管在设置data.data之前登录r会以正确的格式显示正确的数据)

有人能对此有所启发吗?

编辑:添加了我从抓取中获得的回复以及我最终想要得到的回复

例如,数据来自提取网址1:

trafficData

例如数据来自提取网址2:

[{id: '000', cotwoEmissions: 345, utl: 45},{id: '001', cotwoEmissions: 345, utl: 34}]

我在合并中尝试做的事情是有一个对象数组,将这些对象组合在一起,其中id相同且位置相同,utl值被组合并乘以cotwoEmissions值(对于给定的ID)。然后,我基于此向每个对象添加一些额外的属性,并返回一个包含所有对象的新数组。

因此上述内容作为输出将变为:

[{id: '000', cotwoEmissions: 345, utl: 32},{id: '003', cotwoEmissions: 345, utl: 45} ]

1 个答案:

答案 0 :(得分:0)

无法解决所有奇怪的问题,但是在转换函数内部,您首先销毁trafficData项,然后再对其进行修改。这也会修改td变量,因为它保留了对相同项目的引用。

您可能想要的是创建一个具有修改后的值和旧值(已解构)的新对象,并将该新创建的项添加到toReturn中。

一般来说,这是一个好习惯,可以避免这样的混乱,不要修改输入参数,而是在某些级别上进行了更改(如果实际上已更改),则复制并返回一个新对象。 这主要用于以下情况:找不到过滤对象(第一次修改项目),找到对象时,您知道所找到的对象是您在此函数内创建的对象(假设您修改您的代码以创建一个新对象以推送到toReturn),因此再次进行修改应该是安全的。