Don't know what I am doing wrong here, maybe it is a rookie mistake.
I am trying to recreate chess.
My state is delayed by one.. i.e. when I click on square to show possible moves of piece, the possible moves will appear but only after my second click, they will show on the right spot. And for the 3rd click the state from 2nd click will appear on the right spot and so on. What am I doing wrong here? I am sending few code examples from my next.js app.
This is my Square component
export default function Square({
x,
y,
color,
content,
contentClr,
handleClick,
}) {
const col = color == 'light' ? '#F3D9DC' : '#744253';
return (
<div
className='square'
x={x}
y={y}
style={{ backgroundColor: col }}
onClick={() => handleClick(x, y)}
>
{content != '' && (
<h1 style={{ color: contentClr == 'light' ? 'white' : 'black' }}>
{content}
</h1>
)}
</div>
);
}
This is my Board component
import { useState, useEffect } from 'react';
import Square from './square';
import styles from '../styles/Board.module.css';
import rookMoves from './possibleMoves/rookMoves';
export default function Board({ initialBoard, lightTurn, toggleTurn }) {
let size = 8;
const [board, setBoard] = useState(initialBoard);
const [possibleMoves, setPossibleMoves] = useState([]);
//possibleMoves .. each possible move is represented as x, y coordinates.
useEffect(() => {
console.log('board state changed');
}, [board]);
useEffect(() => {
console.log('possible moves state changed');
console.log(possibleMoves);
renderPossibleMoves();
}, [possibleMoves]);
const playerClickOnPiece = (x, y) => {
let pos = getPossibleMoves(x, y, rookMoves, [left, right, up, down]);
setPossibleMoves(pos);
};
//where to is object that has functions for directions in it
const getPossibleMoves = (x, y, movePiece, whereTo) => {
let posMoves = [];
for (let i = 0; i < whereTo.length; i++) {
posMoves = posMoves.concat(movePiece(board, x, y, whereTo[i]));
}
console.log(posMoves);
return posMoves;
};
const renderPossibleMoves = () => {
console.log('board from renderPossibleMoves ', board);
let newBoard = board;
for (let i = 0; i < possibleMoves.length; i++) {
newBoard[possibleMoves[i].y][possibleMoves[i].x] = 10;
}
setBoard(newBoard);
};
const squareColor = (x, y) => {
return (x % 2 == 0 && y % 2 == 0) || (x % 2 == 1 && y % 2 == 1)
? 'light'
: 'dark';
};
const handleClick = (x, y) => {
if (lightTurn && board[y][x] > 0) {
console.log(
`show me possible moves of light ${board[y][x]} on ${x} ${y}`
);
playerClickOnPiece(x, y);
} else if (!lightTurn && board[y][x] < 0) {
console.log(`show me possible moves of dark ${board[y][x]} on ${x} ${y}`);
playerClickOnPiece(x, y);
} else if (board[y][x] == 'Pm') {
playerMove();
}
};
return (
<>
<div className='board'>
{board.map((row, y) => {
return (
<div className='row' key={y}>
{row.map((square, x) => {
return (
<Square
x={x}
y={y}
key={x}
color={squareColor(x, y)}
content={square}
contentClr={square > 0 ? 'light' : 'dark'}
handleClick={handleClick}
playerMove={toggleTurn}
/>
);
})}
</div>
);
})}
</div>
</>
);
}
import { useState } from 'react';
import Board from './board';
let initialBoard = [
[-4, -3, -2, -5, -6, -2, -3, -4],
[-1, -1, -1, -1, -1, -1, -1, -1],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1],
[4, 3, 2, 5, 6, 2, 3, 4],
];
export default function Game() {
const [lightTurn, setLightTurn] = useState(true);
const toggleTurn = () => {
setLightTurn(!lightTurn);
};
return (
<Board
initialBoard={initialBoard}
lightTurn={lightTurn}
toggleTurn={toggleTurn}
/>
);
}
I am sending an example that shows only possible moves with rook but if u click on any light piece.
@juliomalves
's comment helped!
I was mutating state directly in renderPossibleMoves. Spread operator solved the issue.
from
let newBoard = board;
to
let newBoard = [...board];