我应该总是深度克隆 React 的状态吗?

时间:2021-01-02 21:43:04

标签: javascript reactjs

我正在使用 React 开发一个井字游戏。

游戏单元的点击处理程序如下所示:

function onClick(row, cell) {
    if (!state.game[row][cell]) {
        state.game[row][cell] = state.player === 1 ? 1 : 2;
        state.player = state.player === 1 ? 2 : 1;
        setState({ ...state });
    }
}

我基本上是改变旧状态并通过将其属性复制到新对象中(以创建新引用)来将其作为新状态重用。

尽管如此,对 state.game 数组的引用保持不变,所以我想知道这样做是否合适,或者它是否容易出错,以及是否应该始终深度克隆 React 中的状态。

2 个答案:

答案 0 :(得分:1)

此代码可能会导致错误。可能是这个顶级组件没有显示错误,因为它唯一关心的事情有一个新的引用。但是如果你将状态的一部分作为 props 传递给其他组件,它们可能会被突变抛弃。

因此,您应该在要更改的每个级别创建一个副本。例如:

function onClick(row, cell) {
  if(!state.game[row][cell]) {
    const newRow = [...state.game[row]];
    newRow[cell] = state.player === 1 ? 1 : 2;

    const newGame = [...state.game];
    newGame[row] = newRow;

    setState({
      ...state,
      player: state.player === 1 ? 2 : 1,
      game: newGame,
    })
  }
}

答案 1 :(得分:1)

改变状态可能会导致 React 看不到更改并且不会重新渲染您的组件的问题。

如果您的状态很复杂,那么使用 lodash.cloneDeep() 制作副本会更容易,然后对副本进行变异但保持之前的状态不变。

import _cloneDeep from 'lodash/cloneDeep';
...
function onClick(row, cell) {
    if (!state.game[row][cell]) {
        const newState = _cloneDeep(state);
        newState.game[row][cell] = state.player === 1 ? 1 : 2;
        newState.player = state.player === 1 ? 2 : 1;
        setState(newState);
    }
}