更新React数组状态异常

问题描述 投票:0回答:1

更新数组状态没有按预期工作!

我正在制作一个具有以下细节的井字游戏:

我有一个名为 gameBoardState 的状态(一个 3x3 数组),其中包含“X”和“O”的位置,初始值为“null”。

**const initialGameBoard = [
  [null, null, null],
  [null, null, null],
  [null, null, null],
];
**
export default function GameBoard({
  playerTurnHandler,
  onTurn,
  turnLogger,
  participant,
}) {
  **const [gameBoardState, setGameBoardState] = useState(initialGameBoard);**
  const [winner, setWinner] = useState('');
  const [counter, setCounter] = useState(0);
.
.
.
}

当游戏结束时,有一个“重新匹配”按钮,可以将 gameBoardState 设置回初始状态 - 全部为空。

在 onClick 侦听器函数中,我将变量“initialGameBoard”的旧值复制到新的 const 变量中,然后使用该变量作为 setGameBoardState(param) 的参数。没成功:(

我也尝试过 setGameBoardState(initialGameBoard)。也没有成功。

但是当我在 onClick 函数中初始化一个新的 const 变量并直接在 setGameBoardState 中使用该变量时,它确实起作用了!

有人可以向我解释一下为什么会发生这种情况吗?

这是我的完整代码:

import { useState, useSyncExternalStore } from 'react';
import { WINNING_COMBINATIONS } from '../winning-combinations';
import GameOver from './GameOver';

const initialGameBoard = [
  [null, null, null],
  [null, null, null],
  [null, null, null],
];

export default function GameBoard({
  playerTurnHandler,
  onTurn,
  turnLogger,
  participant,
}) {
  const [gameBoardState, setGameBoardState] = useState(initialGameBoard);
  const [winner, setWinner] = useState('');
  const [counter, setCounter] = useState(0);

  function checkWinner(actualGameboardState) {
    const numberOfCombinations = WINNING_COMBINATIONS.length;
    for (let index = 0; index < numberOfCombinations; index++) {
      const firstBlock = WINNING_COMBINATIONS[index][0]; //example = {row: 0, column: 0}
      const secondBlock = WINNING_COMBINATIONS[index][1]; //example = {row: 0, column: 1}
      const thirdBlock = WINNING_COMBINATIONS[index][2]; //example = {row: 0, column: 2}

      if (
        actualGameboardState[firstBlock.row][firstBlock.column] === null ||
        actualGameboardState[secondBlock.row][secondBlock.column] === null ||
        actualGameboardState[thirdBlock.row][thirdBlock.column] === null
      ) {
        continue; //if null, directly check the next combination
      }

      if (
        actualGameboardState[firstBlock.row][firstBlock.column] === 'X' &&
        actualGameboardState[secondBlock.row][secondBlock.column] === 'X' &&
        actualGameboardState[thirdBlock.row][thirdBlock.column] === 'X'
      ) {
        //do something
        setWinner(participant[0].toUpperCase());
      }

      if (
        actualGameboardState[firstBlock.row][firstBlock.column] === 'O' &&
        actualGameboardState[secondBlock.row][secondBlock.column] === 'O' &&
        actualGameboardState[thirdBlock.row][thirdBlock.column] === 'O'
      ) {
        //do something
        setWinner(participant[1].toUpperCase());
      }
    }
  }

  function selectSquareHandler(row, col) {
    const newGbState = [...gameBoardState];
    newGbState[row][col] = onTurn;
    setGameBoardState(newGbState);
    playerTurnHandler();
    turnLogger(row, col, onTurn);
    checkWinner(gameBoardState);
    setCounter((prev) => prev + 1);
  }

  function rematch() {
    const initial = [...initialGameBoard];

    const initial2 = [
      [null, null, null],
      [null, null, null],
      [null, null, null],
    ];

    //setGameBoardState(initial); doesn't work! page isn't re-rendered
    //setGameBoardState(initialGameBoard) also doesn't work
    setGameBoardState(initial2);//works perfectly!
    setWinner('');
    setCounter(0);
    console.log(gameBoardState, winner, counter);
  }

  return (
    <>
      {(winner || counter === 9) && (
        <GameOver winner={winner} rematch={rematch} />
      )}
      <ol id="game-board">
        {gameBoardState.map((row, rowIndex) => (
          <li key={rowIndex}>
            <ol>
              {row.map((playerSymbol, colIndex) => (
                <li key={colIndex}>
                  <button
                    onClick={() => selectSquareHandler(rowIndex, colIndex)}
                    disabled={playerSymbol !== null ? true : false}
                  >
                    {playerSymbol}
                  </button>
                </li>
              ))}
            </ol>
          </li>
        ))}
      </ol>
    </>
  );
}
javascript reactjs arrays state
1个回答
0
投票

问题出在这一行

const newGbState = [...gameBoardState];

Spead 运算符只能浅层复制您的对象/数组,这意味着在嵌套对象/数组的情况下,它们的

ref
将保持不变

解决此问题的一种方法是将上面的代码行更改为类似这样的内容

const newGbState = [];
for(let i=0; i<gameBoardState.length; i++) {
  newGbState[i] = [...gameBoardState[i];
}
© www.soinside.com 2019 - 2024. All rights reserved.