我正在尝试构建一个小型React应用来建模Conway's Game of Life。我建立了一个二维数组来跟踪10×10网格中每个单元的状态。
我正在尝试将此数组存储在State中。在游戏的每个“滴答声”中,我想制作一个数组的副本,评估每个单元格,并可能给它一个新值,然后将副本分配回状态。我以官方React Tutorial为基础,他们使用的是这种精确方法:
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});
}
我的初始方法是使用slice()
,如上面的示例所示。通过调试,我发现这是行不通的。即使我使用各种方法复制状态,但不应该对其进行更改,状态还是会以某种方式被更改。 (我了解,如果我说var x = this.state.blah
和x = 5
因为状态为blah
,所以我更改了状态)
这是我的代码:
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
//});
}
即使setState()
调用已被注释掉,只需分配newSquares[i][j] = //...
就足以以某种方式修改状态。
以下是我在Board组件的构造函数中设置初始数组的代码:
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);
}
我看了一下here,但在点击次数基础上更新正方形没有任何麻烦(我的代码部分工作正常)。各种SO帖子和面对面的故障排除人员建议了三种产生相同问题的不同复制策略。我还看了here。
我对React还是很陌生,通常对JS不太熟练,显然我对State没有很好的了解。这是我的问题:
提前谢谢!我很困惑。
答案 0 :(得分:0)
spread operator仅对值进行浅复制。这意味着,如果其中有任何嵌套值,则将引用它们而不是复制它们。例如:
const a = { field: { innerField: 'test' } };
const b = { ...a } // b === { field: { innerField: 'test' } } SAME field as a
要复制嵌套数组,应使用深度复制方法,例如Lodash's cloneDeep或Ramda's clone
例如,使用Lodash的cloneDeep:
const newSquares = _.cloneDeep(this.state.squares);