首页 > 解决方案 > 在 SocketIO 事件侦听器中调用 setState 后,React 组件未更新

问题描述

我有一个类组件。我在构造函数中添加了这一行:

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:board 是包含对象 {color: [x,y,z], alive: boolean} 的数组数组,我正在获取更改的单元格(死单元格)并将它们标记为板上的死单元,所以理想情况下我会去死细胞的索引,并通过 board[row][col] = {color: [x,y,z], alive: false} 将其标记为死

编辑 3:板的数据结构是 [[{}.{},{}],[{},{},{}]] 我正在更改数组中对象的属性

标签: javascriptnode.jsreactjssocket.io

解决方案


当我使用嵌套objectsarray. 我认为setState不能很好地处理嵌套更新。

另一个问题出在您的代码中。你实际上是在改变state.

let new_board = this.state.board;这里的董事会是一个array。Javascript 不会深度克隆arrayobject. 您正在将 的 分配给refererenceboard array变量。

所以,你能做的只是deep clone董事会array

let new_board = this.state.board.map(item => {...item}); // You may need to handle the multiple levels.

也应该工作JSON.stringyJSON.parse

let new_board = JSON.parse(JSON.stringify(array));

一次,您deep clone拥有state. 您可以修改数据并setState触发重新渲染。

更新 1:

当您使用 Cell 的状态来更新它时。重新渲染时不会更新道具值。

因此,您应该在组件中使用getDerivedStateFromPropsCell使prop数据可用于state.

static getDerivedStateFromProps(props, state) {
    return {
      r: props.clickedColorProps[0],
      g: props.clickedColorProps[1],
      b: props.clickedColorProps[2],
      alive: props.aliveProps
    };
  }

请注意getDerivedStateFromProps即使状态发生变化,也会在组件的每次重新渲染时执行。因此,您应该在方法内部有一个条件来返回正确的数据。


推荐阅读