skip to Main Content

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


  1. 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.

    Login or Signup to reply.
  2. setUsers(newState) is not executed immediately. It works in an async way. This means that everytime you call updateUser from your for loop, the users 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search