Wrestling with promises here…
My users make a single request that requires multiple REST calls on the backend. I store each request made by the user and the two REST responses as an item in a ‘records’ array like so:
[
{
call:userRequest,
responses: [
{
source:source1
response:responseText
},
{
source:source2
response:responseText
}
]
}
]
I use a map function to make the mulitple REST API calls. I process each response using a ‘setThisCall’ method which adds details of each response to an array ‘thisCall’. Once done, ‘thisCall’ is used as The value for ‘responses’ in the ‘records’ array is assigned to ‘thisCall’.
await Promise.all(urls.map(async url => {
fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: messageBody
})
.then((response) => response.json())
.then((data) => {
setThisCall(prev => ([ //sets thisCall
...prev,
{
source: source,
response: data.body
}
]))
})
})).then(()=>{
console.log("now adding to records")
setRecords(prev => ([ //sets records
{
call: requestText,
reponses: thisCall
},
...prev
]))
})
I tried using Promise.all() to let the map function complete the fecthes and processing the responses and using ‘then’ to add the calls to ne next ‘record’ item.
But the final ‘then’ is firing before ‘thisCall’ is built resulting in an empty ‘response’ value in ‘records’.
tl;dr – how do I make ‘setRecords’ happen AFTER the rest of the code has completed?
2
Answers
It is preferable to use the async / await syntax.
Issue
Setter function of useState hook is async in nature.
When
setRecords
is called,thisCall
might not have been updated yet, that is why you’re seeing an emptyresponse
value inrecords
.Solution
Each fetch request returns a new promise that resolves after
setThisCall
is called. It will ensure that all thesetThisCall
are completed beforesetRecords
.