Sai Datta
Sai Datta

Reputation: 935

Array does not update with useState hook and for loop

I am trying to update each element in an array using a for loop

When you click on the 'add all' button, it should start updating each element of the array

The update should happen one after the other, and should be visible in the UI

The array is stored in a useState hook

However, the array is not updating as expected

Here's the link to the CodeSandBox : https://codesandbox.io/s/heuristic-hooks-z3wq7?file=/src/App.js

export default function App() {

  const [users, setUsers] = useState(() => fakeUsers);

  function addHandler(id){
      let arr = cloneDeep(users);
      let i = arr.findIndex((u) => u.id === id);
      arr[i].added = true;
      setUsers(arr);
  };

  async function addAll() {
    for (let i = 0; i < users.length; i++) {
      let id = users[i].id;
      await delay(1000);
      addHandler(id);
    }
  }

  return (
    <div className="App">
      <button onClick={addAll}>add all</button>
      {users.map((e) => (
        <div>
          {e.name}-{e.added ? "YES" : "NO"}
        </div>
      ))}
    </div>
  );
}

Upvotes: 0

Views: 612

Answers (2)

errnesto
errnesto

Reputation: 832

You are using an out of date version of the user array. when the second user is added it uses a reference of the array where none is added.

You can provide a update function to setState to always use the current reference:

setUsers(users => {
  let arr = cloneDeep(users);
  let i = arr.findIndex((u) => u.id === id);
  arr[i].added = true;
  return arr
})

Upvotes: 0

Kid
Kid

Reputation: 1240

Use spread operator instead of cloneDeep.

Also, not sure why you are setting the initial state using arrow function.

here's the updated code

export default function App() {
  const [users, setUsers] = useState(fakeUsers);

  function addHandler(id) {
    let arr = [...users];
    let i = arr.findIndex((u) => u.id === id);
    arr[i].added = true;
    setUsers(arr);
  }

  async function addAll() {
    for (let i = 0; i < users.length; i++) {
      let id = users[i].id;
      await delay(1000);
      addHandler(id);
    }
  }

  return (
    <div className="App">
      <button onClick={addAll}>add all</button>
      {users.map((e) => (
        <div>
          {e.name}-{e.added ? "YES" : "NO"}
        </div>
      ))}
    </div>
  );
}

Upvotes: 1

Related Questions