I am trying to get productInfo by productId from backend. I am iterating over productId and fetching data with axios. But it only iterates one element for every compile. How can i iterate all of them in one execution ?
const useBasket = (location) => {
const [products, setProducts] = useState([]);
const [descriptions, setDescriptions] = useState([]);
console.log("ACCOUNT ID:", location.location.state.accountId);
useEffect(() => {
const getBasket = async () => {
const basketResponse = await Axios.get("http://localhost:8084/accountId/" + location.location.state.accountId);
setProducts(basketResponse.data.products);
};
const getProductInfo = async (props) => {
console.log("INSIDE getProductInfo:",props);
const productResponse = await Axios.get("http://localhost:8081/product/" + props).catch(err => console.log(err));
setDescriptions([...descriptions,productResponse.data.description]);
}
getBasket();
for(let i = 0; i < products.length; i++){
console.log("INSIDE FOR:",products[i]);
getProductInfo(products[i]);
}
}, []);
console.log("DESCRIPTIONS:",descriptions);
return { descriptions };
};
I tried to put the for loop inside of a async function. After that i made await the function call inside of the for loop.
I also put loading section when data is not complete it won’t return.
But none of them worked.
3
Answers
State updates are asynchronous and the closure captures the current value of each of your state variables (which won’t change inside the same closure). You should directly access the values from the response instead and use
await
to ensure the request for products finishes before getting the descriptions.Here is one way to implement it:
getBasket
is an async function. Execution does not wait for it to finish/return before continuing. This means your for loop is referencing a products state variable this is unlikely to have been updated.There are a number of ways around this (assuming you cannot simply modify the product fetch to include descriptions):
You could wrap
getBasket
in a promise and await it before iterating.You could combine your
getProductInfo
function withingetBasket
and iteratebasketResponse.data.products
You could wrap getProductInfo in its own useEffect which is executed when products are updated i.e.
There are a few things that can be changed here, and they all boil down to how to handle stuff that doesn’t happen immediately, like:
Now, there might be different ways to solve this, but here’s the solution with least changes:
getBasket
andgetProductInfo
were moved outside theuseEffect
(optional, for readability)getBasket
also returns the data when it is doneawait
was added before thegetBasket
call