我有一个课堂组件。我已经在构造函数中添加了这一行:
this.handleChangedCells = this.handleChangedCells.bind(this);
我在componentDidMount中注册一个SocketIO侦听器,并调用类似的函数
socket.on("changedCells", this.handleChangedCells);
我正在以控制台方式接收数据。一旦收到,请记录下来。问题在于该函数调用this.setState且不会更新组件。我有
handleChangedCells(data) {
console.log(data);
let new_board = this.state.board;
data.map(arr => {
arr.map(obj => {
new_board[obj.ind[0]][obj.ind[1]] = {
color: obj.color,
alive: obj.alive
};
});
});
this.setState({ board: new_board });
}
我拥有的组件如下:
render() {
return (
<div className="boardContainer" style={container_style}>
{this.state.board.map((row, r_ind) => {
return (
<div className="row" key={r_ind}>
{row.map((col, c_ind) => {
return (
<Cell
key={[r_ind, c_ind]}
cell_row_index={c_ind}
cell_col_index={r_ind}
socketProps={socket}
colorProps={this.state.color}
clickedColorProps={col.color}
aliveProps={col.alive}
/>
);
})}
</div>
);
})}
</div>
);
}
如您所见,该组件取决于我更新的状态,但是该组件未更新...对这里发生的事情有任何了解吗?
编辑:这是指向我的项目https://github.com/Dobermensch/ExpressTest.git的链接,相关文件为/client/components/Game.js
编辑2 :木板是包含对象{color:[x,y,z],alive:boolean}的数组的数组,我正在获取已更改的单元格(死单元格)和标记它们在董事会中已失效,因此理想情况下,我将失效细胞的索引移至董事会,并将其标记为已失效[row] [col] = {color:[x,y,z],live:false}
编辑3 :电路板的数据结构为[[{{.. {},{}],[{},{},{}]],并且我正在更改其中对象的属性数组
答案 0 :(得分:1)
当我同时使用嵌套的objects
和array
时遇到了类似的问题。我认为setState
不能很好地处理嵌套更新。
另一个问题在您的代码中。您实际上是在突变state
。
let new_board = this.state.board;
这里的木板是array
。 JavaScript不会深度克隆array
和object
。您正在将refererence
board
中的array
分配给新变量。
因此,您可以做的只是deep clone
董事会array
。
let new_board = this.state.board.map(item => {...item}); // You may need to handle the multiple levels.
JSON.stringy
和JSON.parse
也应该起作用。
let new_board = JSON.parse(JSON.stringify(array));
一旦您拥有deep clone
中的state
。您可以修改数据,setState
应该触发重新渲染。
更新1:
当您使用单元状态更新它时。道具值在重新渲染时不会更新。
因此,您应该在Cell
组件中使用getDerivedStateFromProps,以使prop
的数据可供state
使用。
static getDerivedStateFromProps(props, state) {
return {
r: props.clickedColorProps[0],
g: props.clickedColorProps[1],
b: props.clickedColorProps[2],
alive: props.aliveProps
};
}
注意,getDerivedStateFromProps
将在组件的每次重新渲染时执行,即使状态改变也是如此。因此,方法中应该有一个条件,可以返回正确的数据。
答案 1 :(得分:0)
请不要使用JSON.parse进行深层复制,这是一个非常糟糕的主意,因为您要为所有内容创建新的对象,而不仅仅是为变化的对象创建新的对象。如果您知道什么是纯组件,那么您就会知道JSON.parse为什么不好。
您可以使用以下代码仅更改需要更改的内容:
handleChangedCells(data) {
console.log(data);
let new_board = [...this.state.board];
data.forEach(arr => {
arr.forEach(obj => {
//shallow copy only if it's not copied already
if (
new_board[obj.ind[0]] ===
this.state.board[obj.ind[0]]
) {
new_board[obj.ind[0]] = [
...new_board[obj.ind[0]],
];
}
new_board[obj.ind[0]][obj.ind[1]] = {
color: obj.color,
alive: obj.alive,
};
});
});
this.setState({ board: new_board });
}
如果它仍然“不起作用”,那么我建议创建一个sandbox来说明问题。除了实际的xhr,您还可以返回更改后的样本数据。
其工作示例为here