Updating state is asynchronous. For example:
const state = {
myValue: 1
}
const someFunctionThatUpdatesState = () => {
console.log("before", state.myValue)
setState({ myValue: 2})
console.log("after", state.myValue)
}
What do you think the console shows?
You might expect it to log before, 1 and after, 2, but what actually gets logged is before, 1, after, 1.
When you set state, you are not actually setting state, you are scheduling a state update. You're basically telling React that state needs to be updated to the value you pass to setState.
React doesn't actually update state until the component re-renders, so in your case, persons will only have the new value once the function ends and the component updates.
Speaking of which, your function has a flaw:
setPersons(persons.concat(personObject))
Since persons does not change until re-render, you are basically cancelling out your setState call on every iteration. You're essentially doing this:
setPersons([].concat(personObject1))
setPersons([].concat(personObject2))
setPersons([].concat(personObject3))
setPersons([].concat(personObject4))
Your result will end up as an array with only the final value in it, all the rest are overwritten.
What you want is something like this:
.then(response => {
console.log('promise fulfilled')
// make sure data actually exists
if (response && response.data) {
// use prev, which is the up-to-date state value
setPersons(prev => [
// spread the current value of `prev`
...prev,
// map the data and spread the resulting array
...response.data.map(item => ({
id: item.id,
content: item.name,
})),
])
}
})
The changes I've made are:
- Check if the data exists! What happens if
data is undefined?
- Use
map instead of forEach. What you're doing is mapping your data array to an array in state, so just use the map function instead of forEach.
- Replace
concat with spread syntax .... It's more succinct and easier to read.
- Only call
setPersons once, and pass a function to setPersons.
If your new state value depends on old state (like with persons, you are appending the new data to the array of old data), you should pass a function to setState. prev is the most up-to-date state value, so you can depend on it. Doing something like setPersons(persons....) (using persons inside setPersons is prone to errors.