reactjschessboard.js

React State Not Updating in Function


Using React, I am trying to make a chess website.

Inside my App function, I have the following code:

const [playerSide, setPlayerSide] = useState('White');
function switchPlayerSide() {
  console.log('in switch, ' + playerSide);
  setPlayerSide(playerSide === 'Black' ? 'White' : 'Black');
}

In my ChessBoard function, there is an onDragStart listener for the chess board that gets called when the user drags a piece:

function onDragStart(source, piece, position, orientation) {
     console.log(playerSide);

     if (game.current.in_checkmate() || game.current.in_draw())
         return false;

    return piece.charAt(0) === playerSide.charAt(0).toLowerCase() && _getSideToMove() === playerSide;
}

Which is supposed to only allow the player to move if the game is not over, they grab the correct piece, and it is their turn to move.

And an onDrop listener:

function onDrop(source, target, piece, newPos, oldPos, orientation) {
    // checks if move is valid
    let _playerMove = game.current.move({ from: source, to: target, promotion: 'q' });
    if (!_playerMove)
        return 'snapback';

    if (onDropListener)
        onDropListener();
}

That makes a move if it is valid and also calls an onDropListener prop.

playerSide and onDropListener are passed as props from the App function, like this:

<ChessBoard playerSide={playerSide} onDropListener={switchPlayerSide}/>

However, in onDragStart and switchSide, the print statement always prints "White" even though I have some prints in the App and ChessBoard functions outside of any functions (so that the print gets called when the page gets re-rendered) that correctly prints out "White" initially and then "Black" after the piece is dropped at a valid square.

Also, by the time I start dragging the pieces after my first drop, enough time should have gone by that setPlayerSide being asynchronous should not be the cause of the problem.

Why is this happening, and how can I fix it?


Solution

  • Try using callback syntax since you are using current state to set new state-

    setPlayerSide((playerSide) => playerSide === 'Black' ? 'White' : 'Black');