Updating state of array didn’t work like expected!
Hi Guys!
I’m making a Tic-Tac-Toe Game with this detail:
I have a state called gameBoardState (an 3×3 array) that contains the position of ‘X’ & ‘O’ with initial value of all ‘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);
.
.
.
}
When the game is over there’s a ‘rematch’ button that set the gameBoardState back to the initial state – which is all null.
Inside the onClick listener function, I copied the old value of the variable ‘initialGameBoard’ into a new const variable and then use this variable as the parameter of setGameBoardState(param). It didn’t work 🙁
I also tried setGameBoardState(initialGameBoard). It didn’t work too.
But when I initialized a new const variable inside the onClick function and directly use this variable inside setGameBoardState it did work!
Can someone explain to me why did it happen?
Thanks!
This is my complete code:
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>
</>
);
}