更新数组状态没有按预期工作!
我正在制作一个具有以下细节的井字游戏:
我有一个名为 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>
</>
);
}
问题出在这一行
const newGbState = [...gameBoardState];
Spead 运算符只能浅层复制您的对象/数组,这意味着在嵌套对象/数组的情况下,它们的
ref
将保持不变
解决此问题的一种方法是将上面的代码行更改为类似这样的内容
const newGbState = [];
for(let i=0; i<gameBoardState.length; i++) {
newGbState[i] = [...gameBoardState[i];
}