Reputation: 59
I'm trying to do what I thought would be pretty straightforward, but is turning out to be pretty hard. Essentially what I want to do is when loading the page, loop through an array of IDs, make a call to two APIs for each ID, merge the responses together for each ID, and save that to a React state variable itemList
.
This is the code I have so far. The two getInfo()
and getOtherInfo()
functions are doing a basic JavaScript Fetch and are returning a Promise and then the decoded JSON data asynchronously no problem. I can even display the returned data on the page as it gets loaded, so that part works fine.
useEffect(() => {
idList.forEach((id) => {
getInfo(id)
.then((response) => {
getOtherInfo(id).then((otherReponse) => {
response.otherInfo = otherResponse;
});
setItemList((itemList) => [...itemList, response]);
})
.catch((error) => console.log("Loading failed: " + error));
});
}, []);
I know that the nested .then()
is wrong, as it's trying to add response data to a potentially unresolved Promise, but it's my first time using React Hooks and the Fetch API so I'm not sure what the right way to do it is. I've found a couple other similar questions, but they don't seem to deal with joining the data together after it gets returned from the two APIs.
Can someone point me in the right direction here?
Upvotes: 1
Views: 2508
Reputation: 1732
I know that the nested .then() is wrong, as it's trying to add response data to a potentially unresolved Promise
If you need the resolved values of response
and otherResponse
before continuing, it's better to put the logic needed inside the inner then()
continuation. This is what you've done when setting response.otherInfo = otherResponse
, but I think the setItemList
call should also be inside that continuation.
useEffect(() => {
idList.forEach((id) => {
getInfo(id)
.then((response) => {
getOtherInfo(id).then((otherReponse) => {
response.otherInfo = otherResponse;
setItemList((itemList) => [...itemList, response]);
});
})
.catch((error) => console.log("Loading failed: " + error));
});
}, []);
If the request to getOtherInfo
is not dependent on the outcome of getInfo
, then it may be beneficial to execute those requests concurrently using Promise.all
.
useEffect(() => {
idList.forEach((id) => {
Promise.all([getInfo(id), getOtherInfo(id)])
.then(([response, otherResponse]) => {
response.otherInfo = otherResponse;
setItemList((itemList) => [...itemList, response]);
})
.catch((error) => console.log("Loading failed: " + error));
});
}, []);
Upvotes: 1
Reputation: 1249
Try this
var promiseArr = [];
idList.forEach((id) => {
promiseArr.push(getInfo(id));
promiseArr.push(getOtherInfo(id));
});
Promise.all(promiseArr).then((resp) => {
console.log(resp);
}).catch((error) => console.log("Loading failed: " + error));
Upvotes: 1