0

I have an object employees that gets updated from user input through setEmployees() inside a function. I don't understand why for loop does not work but map() works to update the value on the webpage. I am not sure if this is react thing or useState() thing or maybe something else that I missed or did not know. Any idea? Thank you.

The employee object that gets updates from useState hook:

  const [employees, setEmployees] = useState([
    {
      id: 0,
      name: "Jason", 
      role: "Engineer", 
      img: 'https://images.pexels.com/photos/2598024/pexels-photo-2598024.jpeg'
    },
    {
      id: 1,
      name: "Abby", 
      role: "Manager", 
      img: 'https://images.pexels.com/photos/2598024/pexels-photo-2598024.jpeg'
    }
  ]);

The case where I use for loop but it does not work:

  function updateEmployee(id, newName, newRole) {

    // Using for loop to update values
    const updatedEmployees = employees
    for (let i of updatedEmployees) {
      if (i.id == id) {
        i.name = newName
        i.role = newRole 
      }
    }
    console.log(updatedEmployees)  // updatedEmployees has been successfully updated
    setEmployees(updatedEmployees) // object `employees` values have been updated but the update does not show on the webpage
  }

The case where I use map() and it works:

  function updateEmployee(id, newName, newRole) {
    
    // Using map() to update values
    const updatedEmployees = employees.map((employee) => {
      if (id == employee.id) {
        return {...employee, name: newName, role: newRole}
      }
      return employee
    })

    setEmployees(updatedEmployees) // object `employees` values have been updated and also update the values shown on the webpage
  }
Jason T.
  • 113
  • 1
  • 2
  • 7
  • I'm assuming `setEmployees` is a `useState` hook, as default React does a shallow compare, if you update an object it will be the same instance, that's why map works because you are creating a new instance. You could do -> `setEmployees([...employees])`, – Keith Jan 02 '23 at 01:26
  • @Keith thanks! but I am assigning it to a new object `updatedEmployee`. It shouldn't be the same as the original one, right? – Jason T. Jan 02 '23 at 01:33
  • No,.. Your just updating the original object in the for loop version. Your kind of doing this -> `let obj1 = {}; let obj2 = obj1; obj2.x = 'hello'; console.log(obj1 === obj2);` If you run that code you will see the answer is `true`.. IOW: `obj1` & `obj2` are the same, and in React that means there has been no change.. – Keith Jan 02 '23 at 01:37
  • I did `console.log(employees == updatedEmployees)` to compare this two objects when using for loop and I entered the new values from user inputs and it shows `true`, which I don't understand why.... – Jason T. Jan 02 '23 at 01:50
  • 2
    It's mainly this -> `const updatedEmployees = employees` your not actually creating a new `object`, but just creating a reference to the existing one. When you used `map`, your actually creating a new array, and mapping the values into it. To make `updateEmployees` a new array, you could also do -> `const updatedEmployees = [...employees]`.. eg.. `let a = [1,2,3]; let b = [...a]; console.log(a === b);` will return false as expected. – Keith Jan 02 '23 at 02:00
  • 1
    This link might help -> https://javascript.info/object-copy – Keith Jan 02 '23 at 02:03
  • 1
    This link might help too. > https://stackoverflow.com/questions/34426458/javascript-difference-between-foreach-and-map – Javatar Jan 02 '23 at 02:04
  • Oh I got it. Thank you very much! Now I understand! And yes, it works when I changed it to `const updatedEmployees = [...employees]`, so this creates a new object, rather than just a reference as previously. – Jason T. Jan 02 '23 at 02:04

0 Answers0