I am mapping through this dummyAssests array and want to create a new array of objects based on the axios response called newAssetArray. But when I console.log the newAssetArray it just contains an array of Promises...
useEffect(() => {
let newAssetArray = dummyAssets.map(async function (asset) {
return await axios
.get(currrentPrice(asset.asset_id))
.then((response) => {
let cp = response.data.market_data.current_price.eur;
let value = Number(cp) * Number(asset.amount);
return { ...asset, value: value };
})
.catch((error) => console.log(error.response.data.error));
});
setAssets(newAssetArray);
console.log(newAssetArray);
}, [dummyAssets]);
Console:
CodePudding user response:
Yes, that is expected. Use Promise.all()
to wait for all the promises to resolve. .map()
itself is not promise aware so it does not "wait" for each individual iteration of its loop to resolve before going onto the next one. So, you have the result of calling N async
functions which all return a promise as your .map()
result. That is how the code is supposed to work. The await you are using it not accomplishing anything. If you use a for loop instead (which is promise-aware, then your loop will be sequenced.
Here's how you could use Promise.all()
to get the results:
useEffect(() => {
Promise.all(dummyAssets.map(function(asset) {
return axios
.get(currrentPrice(asset.asset_id))
.then((response) => {
let cp = response.data.market_data.current_price.eur;
let value = Number(cp) * Number(asset.amount);
return { ...asset, value: value };
}).catch((error) => {
console.log(error.response.data.error)
throw error;
});
})).then(newAssetArray => {
console.log(newAssetArray);
setAssets(newAssetArray);
}).catch(err => {
// do something to handle the error here
});
}, [dummyAssets]);
Or, you might find this implementation a bit simpler to follow:
useEffect(async () => {
try {
const newAssetArray = await Promise.all(dummyAssets.map(async function(asset) {
const response = await axios.get(currrentPrice(asset.asset_id));
const cp = response.data.market_data.current_price.eur;
const value = Number(cp) * Number(asset.amount);
return { ...asset, value: value };
}));
console.log(newAssetArray);
setAssets(newAssetArray);
} catch (e) {
// do something to handle the error here
console.log(e);
}
}, [dummyAssets]);
Also, note that a structure such as:
async function someFunction() {
return await axios.get()
}
does nothing different than just:
async someFunction() {
return axios.get()
}
They both return a promise that resolves to whatever axios.get()
resolves to. The first returns a promise because it's in an async function and ALL async functions return a promise at the point they hit the first await
. The second returns a promise because you're directly returning the axios.get()
promise. Either way, they both return a promise that resolves to the same thing.
So, in general return await fn()
is not helping you vs just return fn()
and is not recommended. Then, once you stop using await
there, you don't need async
for that .map()
callback anymore either.