Saurav Kumar
Saurav Kumar

Reputation: 155

React state changing on change copy of original state?

I am trying to make a simple game like purple pairs in Purple palace game using React. I have a method named clickBtn, it is supposed to increment the count on click and decrement on second click but I don't know why the handleClick method is changing chosen and clicked property of state even if a copy of the new state is made without using setState method. Can you help me fix this?

class GameBoard extends React.Component {
  constructor() {
    super();
    this.state = {
      score: 0,
      time: 0,
      list: [...generateObList(), ...generateObList()],
      count: 0
    };
  }

  handleClick = (id) => {
    this.clickBtn(id);
    const list = this.state.list.slice();
    const current = list.find((a) => a.id === id);
    for (let x of list) {
      if (x.clicked && x.value == list.find((a) => a.id == id).value) {
        x.chosen = true;
        x.clicked = false;
        current.chosen = true;
        current.clicked = false;
        // this.setState((prev) => ({
        //   list: prev.list.map((el) =>
        //     el.id === id ? current : el.value === current.value ? x : el
        //   ),
        //   score: prev.score + 1
        // }));
      }
    }
  };

  clickBtn = (id) => {
    const current = this.state.list.slice().find((e) => e.id === id);
    let deClick = current.clicked;
    current.clicked = !current.clicked;
    console.log(current);
    this.setState(
      (prev) => ({
        list: prev.list.map((el) => (el.id === id ? current : el)),
        count: prev.count + (deClick ? -1 : 1)
      }),
      () => {
        console.log(this.state.count, deClick, current);
      }
    );
  };

  render() {
    const boardStyle = {
      gridTemplateColumns: `repeat(5, 1fr)`,
      gridTemplateRows: `repeat(5,1r)`
    };
    let list = this.state.list.map((n) => (
      <Card
        value={n.value}
        onClick={(e) => {
          this.handleClick(n.id);
        }}
        show={!n.chosen}
      />
    ));
    return (
      <div class="gameBoard" style={boardStyle}>
        {list}
      </div>
    );
  }
}

Upvotes: 0

Views: 1665

Answers (1)

Dilshan
Dilshan

Reputation: 3001

slice() just return a shallow copy of the array so both original and copy refer to the same array items if the items are reference type ( objects ).

For object slice copies object references into the new array. Both the original and new array refer to the same object. If a object changes, the changes are visible to both the new and original arrays.

Try to deep copy the objects. You can easily do deep copy by using, JSON.parse(JSON.stringify(arr))

Also you can try lodash's cloneDeep() method.

For more details about deep cloning - https://stackoverflow.com/a/122704/11306028

Upvotes: 2

Related Questions