How come the updateUser()
function is getting the old users even though I have used useCallback and put users
in the dependency
Ideally the output when clicking update button should be like this
{"id":1,"name":"John","age":10,"gender":"male"}
{"id":2,"name":"Stacy","age":15,"gender":"male"}
{"id":3,"name":"Kevin","age":30,"gender":"male"}
{"id":4,"name":"Jessi","age":13,"gender":"male"}
but in current output only the last user is getting updated
{"id":1,"name":"John","age":10}
{"id":2,"name":"Stacy","age":15}
{"id":3,"name":"Kevin","age":30}
{"id":4,"name":"Jessi","age":13,"gender":"male"}
import { useCallback, useState } from "react";
import "./styles.css";
export default function App() {
const data = [
{ id: 1, name: "John", age: 10 },
{ id: 2, name: "Stacy", age: 15 },
{ id: 3, name: "Kevin", age: 30 },
{ id: 4, name: "Jessi", age: 13 }
];
const [users, setUsers] = useState(data);
const updateUser = useCallback(
(newUser) => {
console.log(users);
const newState = users.map((user) =>
user.id === newUser.id ? newUser : user
);
setUsers(newState);
},
[users]
);
const startUpdate = () => {
for (const user of users) {
updateUser({ ...user, gender: "male" });
}
};
return (
<div className="App">
{users.map((user) => {
return <p key={user.id}>{JSON.stringify(user)}</p>;
})}
<button onClick={startUpdate}>update</button>
</div>
);
}
2
Answers
That’s because you are calling updateUser multiple times in a row. Each time it is called, you’re setting the state. Changes to state are not instant in react. So each sequential call will overwrite the previous one and you’ll end up with just the final entry being updated.
In your example, the best way to do it would be in your
startUpdate
function you can manipulate the dataset, store it in a separate variable and then update the state by passing the entire object.setUsers(newState)
is not executed immediately. It works in an async way. This means that everytime you callupdateUser
from your for loop, theusers
state won’t be updated yet and every call will get to see the original state, as it was at the beginning of the for loop.So the last call to
setUsers(newState)
will override the state with the first original state and the updated last user.