2
\$\begingroup\$

I have found similar posts which has some optimizations on Winning-checking logic: React Tic Tac Toe

My primary focus for this post is about hook setters being asynchronous. So to check if anyone wins, I used useEffect to listen to the board.

  useEffect(
    () => {
      if (winning()) {
        setMessage(`Player ${turn % 2 ? 1 : 2} wins!`);
        setGameState("stopped");
      } else {
        setTurn(turn + 1);
      }
    },
    [board]
  );

When the move is made, the turn number won't increase when the game is finished.

However this makes the initial "turn number" 0 (so the effect adds to it to get 1).

Should I make the board update synchronous before calling the setters? (like using a tempBoard = {...board, (new move)} and check there instead?

Full code (Click handler is step)

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [turn, setTurn] = useState(0);
  const [message, setMessage] = useState("");
  const [gameState, setGameState] = useState("playing");
  const [board, setBoard] = useState({});

  const winning = _ => {
    return (
      (board[0] &&
        board[1] &&
        board[2] &&
        board[0] === board[1] &&
        board[1] === board[2]) ||
      (board[3] &&
        board[4] &&
        board[5] &&
        board[3] === board[4] &&
        board[4] === board[5]) ||
      (board[6] &&
        board[7] &&
        board[8] &&
        board[6] === board[7] &&
        board[7] === board[8]) ||
      (board[0] &&
        board[3] &&
        board[6] &&
        board[0] === board[3] &&
        board[3] === board[6]) ||
      (board[1] &&
        board[4] &&
        board[7] &&
        board[1] === board[4] &&
        board[4] === board[7]) ||
      (board[2] &&
        board[5] &&
        board[8] &&
        board[2] === board[5] &&
        board[5] === board[8]) ||
      (board[0] &&
        board[4] &&
        board[8] &&
        board[0] === board[4] &&
        board[4] === board[8]) ||
      (board[2] &&
        board[4] &&
        board[6] &&
        board[2] === board[4] &&
        board[4] === board[6])
    );
  };

  useEffect(
    () => {
      if (winning()) {
        setMessage(`Player ${turn % 2 ? 1 : 2} wins!`);
        setGameState("stopped");
      } else {
        setTurn(turn + 1);
      }
    },
    [board]
  );

  const step = (n, turn) => {
    if (gameState === "playing" && !board[n]) {
      setBoard({ ...board, [n]: turn % 2 ? "x" : "o" });
    }
  };

  return (
    <div className="App">
      Turn {turn}
      <div className="container">
        {[0, 1, 2, 3, 4, 5, 6, 7, 8].map(n => (
          <div key={"b" + n} className={"b" + n}>
            <button onClick={_ => step(n, turn)}>{board[n] || " "}</button>
          </div>
        ))}
      </div>
      {message}
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

CodeSandbox

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.