Home > Enterprise >  Why does array not update when using forEach?
Why does array not update when using forEach?

Time:12-24

I have the following code in a React project:

changeChecked (task){
    this.setState(prevState => {
      let copy = [...prevState.tasks];
      copy.forEach((item, index) => {
        if (item == task) {
          copy[index].checked = !copy[index].checked;
        }
        console.log(item);    
        // {name: "Task A", checked : true}
        // {name: "Task B", checked : false}
      });
      console.log(copy);
      // [
      //      {name : "Task A", checked : false},
      //      {name : "Task B", checked : false}
      // ]
      return {tasks : copy}
    });
 }

the initial state of the "this" (a React component) is this:

{
  tasks : [
    {name : "Task A", checked : false},
    {name : "Task B", checked : false}
  ]
}

When I call that function (by button click) with the first task in the state.tasks as parameter, the forEach loop seems to change the item (see commented lines), but afterwards the "copy" array is unchanged. How so? When I execute this exact logic in an interactive javascript interpreter, the copy does have this first task changed.

enter image description here

EDIT: Now I see something very weird. When I expand the printed out object (line 8) in the console by clicking on it, I get this:

enter image description here

Console sais checked is true, but in the expanded view of the object it sais checked is false. What is going on here?

CodePudding user response:

I suppose it's because you're trying to compare two objects, similarly to such case:

let task = {name: "Task A", checked: false};
let item = {name: "Task A", checked: false};
task == item;  // results to false

so in your case, condition if (item == task) { will always result to false. One of the idea would be to compare some key parts of the task/item attributes like name, or provide some unique identifier.

CodePudding user response:

I haven't posted on SO so I can't comment on Filip Górczyński's thread but it seems like the copy should get updated if you have the conditional set correctly like they stated. I didn't test this in React as I haven't used class components in forever but doing this:

const tasks = [
    { name: "Task A", checked: false },
    { name: "Task B", checked: false }
]

let copy = [...tasks];
copy.forEach((item, index) => {
    if (item.name == "Task A") {
        copy[index].checked = !copy[index].checked;
    }
    console.log(index, item);
});
console.log(copy);

gives this in the console:

0 { name: 'Task A', checked: true }
1 { name: 'Task B', checked: false }
[
  { name: 'Task A', checked: true },
  { name: 'Task B', checked: false }
]

I think if you were to either use JSON.stringify like Dream Bold said so you can compare the objects as strings or maybe adding another property to tasks for comparison would make it work as your logic seems to check out otherwise.

  • Related