I have a React functional component with state array users
that is successfully being updated with new elements. I know it’s an async process and useEffect
confirms when the state update has finished. I can also see the results in React DevTools.
My issue is that even after useEffect confirms the state update, referencing users
always returns an empty array?
Code exhibiting the problem:
function App() {
const [users, setUsers] = useState([])
const tests = [
{ "id": 1, "name": "Fred" },
{ "id": 2, "name": "Fred" },
{ "id": 3, "name": "Fred" },
{ "id": 4, "name": "Joe" },
{ "id": 5, "name": "Joe" },
]
const runTests = async () => {
const timeout = (n) => { return new Promise( res => setTimeout(res, n) ) }
for (let i = 0; i < tests.length; i++) {
console.log('Start processing array index', i)
// This always reports the users state array is empty []
console.log('users state before', users)
if (users.filter(user => user.name == tests[i].name).length == 0) {
setUsers((users) => [...users, { "name": tests[i].name }])
}
console.log('Sleep Start')
// useEffect reports the users state was updated here, showing the correct contents
await timeout(2*1000)
console.log('Sleep Finish')
console.log('users state after', users)
// This always reports the users state array is empty []
}
}
useEffect(() => {
runTests()
}, []);
useEffect(() => {
console.log('useEffect reported state update to:', users)
}, [users]);
return (
<>
{
users.map((user, id) => {
return <div key={id}>{user.from_call}</div>
})
}
</>
)
}
Console output:
App.jsx:19 Start processing array index 0
App.jsx:20 users state before []
App.jsx:26 Sleep Start
App.jsx:40 useEffect reported state update to: []
App.jsx:40 useEffect reported state update to: [{…}]
App.jsx:29 Sleep Finish
App.jsx:30 users state after []
App.jsx:19 Start processing array index 1
App.jsx:20 users state before []
App.jsx:26 Sleep Start
App.jsx:40 useEffect reported state update to: (2) [{…}, {…}]
App.jsx:29 Sleep Finish
App.jsx:30 users state after []
App.jsx:19 Start processing array index 2
App.jsx:20 users state before []
App.jsx:26 Sleep Start
App.jsx:40 useEffect reported state update to: (3) [{…}, {…}, {…}]
App.jsx:29 Sleep Finish
App.jsx:30 users state after []
App.jsx:19 Start processing array index 3
App.jsx:20 users state before []
App.jsx:26 Sleep Start
App.jsx:40 useEffect reported state update to: (4) [{…}, {…}, {…}, {…}]
App.jsx:29 Sleep Finish
App.jsx:30 users state after []
App.jsx:19 Start processing array index 4
App.jsx:20 users state before []
App.jsx:26 Sleep Start
App.jsx:40 useEffect reported state update to: (5) [{…}, {…}, {…}, {…}, {…}]
App.jsx:29 Sleep Finish
App.jsx:30 users state after []
1