I'm attempting to build a small react app to model Conway's Game of Life. I've set up a two-dimensional array to track the state of each cell in a 10-by-10 grid.
I'm attempting to store this array in the State. At each "tick" of the game, I want to make a copy of the array, evaluate each cell, potentially giving it a new value, and then assign the copy back to state. I'm basing this off of the official React Tutorial where they use this exact approach:
handleClick(i) {
//Make a copy from state
const squares = this.state.squares.slice();
//Make some changes to it
squares[i] = 'X';
//Set state to the new value
this.setState({squares: squares});
}
My initial approach was to use slice()
as in the example above. Through debugging, I discovered that this didn't work; somehow state is being changed even though I have used various methods to copy it that shouldn't make changes to it. (I understand that if I say var x = this.state.blah
and x = 5
that I have changed state because blah
is a reference to it)
Here is my code:
doTick = () => {
console.log("doin a tick");
console.log(this.state.squares);
//None of these approaches works
//Three different copy strategies all fail
//const newSquares = Object.assign({}, this.state.squares);
//const newSquares = [...this.state.squares];
//const newSquares = this.state.squares.slice();
const newSquares = this.state.squares.slice();
const origSquares = [...this.state.squares];
//Iterating over the array
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
newSquares[i][j] = evaluateCell(origSquares[i][j], this.countLiveNeighbors(i, j, origSquares));
//evaluateCell(origSquares[i][j], this.countLiveNeighborsAndLog(i, j, origSquares));
}
}
//this.setState({
//squares: newSquares
//});
}
Even though the setState()
call is commented out, just having the assignment of newSquares[i][j] = //...
is enough to somehow modify state.
Here's the code where I set up the initial array in the constructor for the Board component:
constructor(props) {
super(props);
var array = new Array(10);
for (var i = 0; i < 10; i++) {
array[i] = new Array(10).fill(false);
}
this.state = {
squares: array
};
console.log(this.state.squares);
}
I took a look here but I'm not having any trouble updating the squares based on clicks (that part of my code works fine). Various SO posts and in-person troubleshooters suggested the three different copy strategies that all produce the same problem. I also took a look here.
I'm very new to React and not very skilled in JS generally, and obviously I don't have a good handle on State. Here are my questions:
- How can I make a copy of state/part of state/data in state in such a way that the copy is not a reference to state? I want to be able to change this new data without changing state (until I am ready).
- Why are the methods used above NOT working properly? The documentation for slice() assures me that I'm getting a copy and not a reference.
Thanks in advance! I'm very confused.