Reputation: 495
Hey ReactJs Community,
I am fairly new to ReactJs and have gotten my first components set up. Now I'm at a point where I would like to update all state items on a specific event. I am looping each state item via map()
and am calling a asynchronous method to determine a value to be included in the state.
This method is returning GET data via the callback function.
updateItems: function() {
var items = this.state.items;
items.map(function(item, i) {
checkConfirmation(item.hash, function(confirmations) {
console.log("Item " + i + " has " + confirmations + " confirmations!");
items[i].hash = item.hash + " (" + confirmations + ")";
items[i].completed = true;
});
});
}
How can I update my state from the asynchronous callback?
I tried passing in this
as the second parameter in map()
and I tried calling setState
after the map() function, but that cannot work since it will be called before any data is returned in the callback.
Thank you for taking time to help me with this issue!
Upvotes: 2
Views: 1680
Reputation: 45121
You can make a promise for each pending request. Await them all using Promise.all
. And set state when all requests are done.
updateItems: function() {
const items = this.state.items;
const pending = items.map(item => new Promise(resolve => {
checkConfirmation(item.hash, resolve)
}))
Promise.all(pending)
.then(confirmations => confirmations.map((confirmation, i) => {
const item = items[i]
// copy items mutating state is bad
return Object.assign({}, item, {
completed: true,
hash: `${item.hash}(${confirmation})`
})
}))
.then(items => this.setState({ items })
}
UPD Callbacks hackery
updateItems: function() {
const items = this.state.items;
let confirmations = []
let loaded = 0
const addConfirmation = i => confirmation => {
confirmations[i] = confirmation
loaded++;
// if all were loaded
if(loaded === items.length) allConfirmationsLoaded()
}
const allConfirmationsLoaded = () => {
const newItems = confirmations.map((confirmation, i) => {
const item = items[i]
// copy items mutating state is bad
return Object.assign({}, item, {
completed: true,
hash: `${item.hash}(${confirmation})`
})
})
this.setState({items: newItems})
}
// for each item lauch checkConfirmation
items.forEach((item, i) => {
checkConfirmation(item.hash, addConfirmation(i))
})
}
Upvotes: 2