0

I am new to React and I am trying to know when does the state object is affected when I do a copy to an object in it.

In the following code; The first scenario causes the state object to be updated, but the second NOT. I need to know what is the difference and Why this is happening?

import React, { Component } from "react";

export class Test extends Component {
  state = {
    counters: [
      { id: 1, desc: "Item1 default description" },
      { id: 2, desc: "Item2 default description" }
    ]
  };
  handleAction() {
    const counters = { ...this.state.counters };

    ////First Scenario
    console.log("Item description before updating:", counters[0].desc);
    counters[0].desc = "Item1 description updated successfully!"; //<--This line makes the state updated
    console.log("Item description after updating:", counters[0].desc);
    console.log(
      "Item description value in state object:",
      this.state.counters[0].desc //Item value is updated in the state object.
    );

    ////Second Scenario

    // console.log("Item description before updating:", counters[0].desc);
    // counters[0] = { id: 1, desc: "Item1 description updated successfully!" }; //<--This line does NOT affect the state
    // console.log("Item description after updating:", counters[0].desc);
    // console.log(
    //   "Item description value in the state object:", //Item value is NOT updated in the state object.
    //   this.state.counters[0].desc
    // );
  }

  render() {
    return (
      <React.Fragment>
        {this.state.counters[0].desc}
        <button
          className="btn btn-danger btn-sm"
          onClick={() => this.handleAction()}
        >
          Check Item description in state object
        </button>
      </React.Fragment>
    );
  }
}

Mohamed Hasan
  • 207
  • 4
  • 13

3 Answers3

2

In JS objects are passed by reference. And the following syntax copies the array but does not copy the objects stored in it. It is called a shallow copy.

const counters = { ...this.state.counters };

In the first case, you are updating the reference to the object that is also referenced by the state variable.

But when you are assigning an element of the array you are creating a new object that the state does not know about therefore it is not modified.

Sol
  • 21
  • 1
  • 5
Teivaz
  • 5,462
  • 4
  • 37
  • 75
0

You need to update state using setState. Mutate state directly is something that you shouldn't be doing: https://reactjs.org/docs/state-and-lifecycle.html#do-not-modify-state-directly

Oriol Grau
  • 609
  • 6
  • 8
  • I know, But I just need to understand the difference that makes it changes in the first scenario and not changing in the second one. What happens in memory exactly? – Mohamed Hasan Oct 05 '19 at 09:02
0

The spread operator { ...obj } does a shallow copy, meaning it only duplicates the structure of counter array in this case and not the content of each element.

Meaning the addresses or reference of counter[0] and counter[1] are duplicated not the objects they hold. So updating counter[0].desc will also update the desc property in the original state object.

But updating counter[0] only updates the duplicate and does not affect the original copy in the state object.

Check this post to get a better understanding of shallow and deep copy.

I must also add that you should always update the react state using this.setState in order to avoid unexpected outcomes.

Finally, some people will argue about using nested properties because React is not oriented to work with nested state. Maybe this is correct or not but here's what I think:

I would suggest you avoid using nested state, if you must then endeavour to make it as light as possible because the downside is every tiny piece of change will recreate the parent object, which is not good for performance.

Andrew Quartey
  • 101
  • 2
  • 7
  • Now I got the point; Does this means that the shallow copied object (counters) holds a set of references to the elements in the main object inside the state object; And NOT this shallow copied element (Itself) holds a reference to the object inside the state? – Mohamed Hasan Oct 05 '19 at 10:56
  • Yes the objects in the shadow copied element are the same as that in the state object. but the element itself is a duplicate. So the duplicate holds the same object in the state. – Andrew Quartey Oct 05 '19 at 12:16