0

I'm pretty good in Vue and React raising just a lot questions to me.

I'm doing variation of tic-tac-toe game just to see how React works. I wrote it and it works just fine but with delay 1 move and I don't know why. Here is a part of a code

function App() {

  let [board, setBoard] = useState([
      null, null, null,
      null, null, null,
      null, null, null
  ]);
  let [turn, setTurn] = useState('X');

    let checkWinner = () => {
        console.log(board, 'board in checkWinner'); // board is not updated
        if((board[0] === board[1] && board[1] === board[2] && board[1] !== null) ||
            (board[3] === board[4] && board[4] === board[5] && board[4] !== null) ||
             (board[6] === board[7] && board[7] === board[8] && board[7] !== null)){
            console.log("We have a winner")
            setBoard(Array(9).fill(null))
        }
    }

  let cellClicked =  (i) => {
      let newBoard = [...board];
      newBoard[i] = turn;

      setTurn(turn === 'X' || !turn ? 'O' : 'X');
      setBoard(newBoard);
      console.log(newBoard); // board is updated
      checkWinner();
  }

.
.
.

that's not a whole code, but a part where I have an issue. Function cellClicked() is triggered when in child component was pressed button. Then it sets a new board and in console.log is clearly updated as it expected, then by the end of this function triggers checkWinner and that is where I have problem. In console.log it shows me that board wasn't updated. When I press next times - first console shows everything good, but second console shows with 1 step delay. Why is that ? Thank you! async - await didn't help

Eldar Tailov
  • 358
  • 5
  • 18
  • React state updates are asynchronous and processed *between* render cycles. When `checkWinner` is called from `cellClicked` state has yet to update and will continue using the current state value until at least the function that enqueued the update completes and is popped off the callstack. You should use an `useEffect` hook to issue the side-effect of checking for a winner and resetting the game board. – Drew Reese Nov 23 '20 at 23:01
  • It's async but doesn't return a Promise. You need `useEffect(() => { /* do something after board changes */ }, [board]);` –  Nov 23 '20 at 23:03
  • I think you should call your checkWinner function in a useEffect(() => { checkWinner(); }, [board]} To ensure to check the winner when the board is updated. – Ben Nov 23 '20 at 23:04
  • @ChrisG React state updates ***are not*** `async`. `async` functions implicitly return a Promise. – Drew Reese Nov 23 '20 at 23:04
  • @DrewReese I know; I'm obviously talking about the English word "asynchronous", not the JS keyword that implicitly returns a Promise, which calling the state setter doesn't do, like I just said... I'm telling OP that they have correctly identified the cause of the issue but it's still not a Promise. The command is async(hronous) though. –  Nov 23 '20 at 23:06
  • @ChrisG Is it obvious though? To a novice? Saying something is "async" in JS has a completely different meaning than saying some code is asynchronously processed. It's a small yet very important distinction. I suggest sticking to the full English word if you don't actually mean the keyword `async`, if for anything, to disambiguate your comments. – Drew Reese Nov 23 '20 at 23:11
  • @DrewReese I get your point, but given the entire context (OP being new to React but not JS, OP knowing about async & Promises etc.) I didn't think my comment was ambiguous. In any case, it's should be pretty clear by now. –  Nov 23 '20 at 23:21
  • anyhow. Thank you for examination, I figured it out) Thanx) – Eldar Tailov Nov 24 '20 at 02:56

0 Answers0