简体   繁体   English

Promise 返回意外结果

[英]Promise returning unexpected result

I'm quite new to promises and use state but I have been looking at this for hours and i can't understand what the issue here but it may be my understanding of promises.我对 Promise 很陌生,使用 state 但我已经看了好几个小时了,我不明白这里的问题是什么,但这可能是我对 Promise 的理解。 Any help would be appreciated.任何帮助,将不胜感激。

I have a component that is hydrated with props from a response api:我有一个组件用来自响应 api 的道具进行水合:

const [trafficData, setTrafficData] = useState();

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

<TrafficWidget incomingData={trafficData} />

traffic widget component交通小部件组件

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}</>)
}

The method for the api returned in a promise which is consumed by my app is here:在我的应用程序使用的 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);
    }
  });

the data that comes back from this method is an array of objects: [{...}, {...}, etc] which I can see in the console.从这个方法返回的数据是一个对象数组: [{...}, {...}, etc] ,我可以在控制台中看到。

What I can't understand is why the variable from the callback, the td on the.then in getTrafficDetails is now updated with the new metadata even though I copied it.我无法理解的是为什么回调中的变量, getTrafficDetails中的td上的 td 现在使用新的元数据进行更新,即使我复制了它。

Even weirder, when i inspect the data going into the TrafficWidget component from this method, it transforms into an object with the requested data inside it, with strangely with length 0, in the form of {data: [{},{}]} which if i then access in the TrafficWidget component via data.data , causes an infinite loop which causes a crash.更奇怪的是,当我检查从此方法进入TrafficWidget组件的数据时,它会转换为 object,其中包含请求的数据,长度为 0,格式为{data: [{},{}]}如果我随后通过data.data访问 TrafficWidget 组件,则会导致无限循环,从而导致崩溃。 (although logging r before setting trafficData shows the correct data in the correct format) (尽管在设置trafficData之前记录r以正确的格式显示正确的数据)

Can anyone shed some light on this?任何人都可以对此有所了解吗?

edit : added response that I receive from the fetch and what i'm trying to end up with编辑:添加了我从 fetch 收到的响应以及我想要得到的结果

eg data coming from fetch url 1:例如来自获取 url 1 的数据:

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

eg data coming from fetch url 2:例如来自 fetch url 2 的数据:

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

what i try and do in the merge is have an array of objects which combine these where the id is the same and where they are the same, the utl values are combined and multiplied by the cotwoEmissions value (which are the same for a given id).我在合并中尝试做的是有一个对象数组,它们将这些对象组合在一起,其中 id 相同并且它们相同,utl 值被组合并乘以 cotwoEmissions 值(对于给定的 id 相同)。 I then add some extra properties to each object based on this and return a new array with all of the objects.然后我基于此为每个 object 添加一些额外的属性,并返回一个包含所有对象的新数组。

so the above, as an output would become:所以上面,作为 output 将变为:

[{id: '000', cotwoEmissions: 345, utl: 77, totalEmission: 26,565, totalEmissionFormatted: '26,565'},{id: '001', cotwoEmissions: 345, utl: 1, totalEmission: 345, totalEmissionFormatted: '345'}, {id: '003', cotwoEmissions: 100, utl: 2, totalEmission: 200, totalEmissionFormatted: '200'}]

Can't answer for all the strangeness but inside your transformation function, you first destruct the trafficData item but then also modify it.无法回答所有的奇怪问题,但是在您的转换 function 中,您首先破坏了 trafficData 项,然后还对其进行了修改。 This will modify the td variable as well since it keeps a reference to the same items.这也将修改 td 变量,因为它保留对相同项目的引用。

What you likely want is to instead create a new object with the modified values and old values (that you destructured) and add that newly created item into toReturn instead.您可能想要的是使用修改后的值和旧值(您已解构)创建一个新的 object,并将新创建的项目添加到 toReturn 中。

This is good practice in general to avoid confusion like this, don't modify input parameters, instead copy and return a new object on each level if something has actually changed.一般而言,这是一种避免混淆的好习惯,不要修改输入参数,而是在每个级别复制并返回一个新的 object 如果实际发生了变化。 This is mostly for the case of when you don't find the filteredObject (the first time you modify an item), when you find the object you know that the object you found is an object you've created inside this function (assuming you modify your code to create a new object to push into toReturn) so it should be safe to modify again. This is mostly for the case of when you don't find the filteredObject (the first time you modify an item), when you find the object you know that the object you found is an object you've created inside this function (assuming you修改您的代码以创建一个新的 object 以推入 toReturn),因此再次修改应该是安全的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM