состояние не проверяется правильно внутри функции обработчика щелчка в следующем js

# #javascript #reactjs #firebase #next.js

Вопрос:

Я создаю многопользовательскую онлайн-игру в крестики-нолики с firebase и next-js. В этой игре я хочу проверить ход игроков, т. е. Если следующий ход будет «O», то «X» не сможет изменить ни одну плитку и ее расположение. Фиксированный ход кулака всегда «X» в игре, и я создал переменную состояния под названием isNextO

    const [isNextO, setIsNextO] = useState("yes");
 

что изначально означает «да», но когда «О» выполняет свой ход, он меняет состояние на «нет» следующим образом

    var isTurn = isNextO === "yes" ? "no" : "yes";
   setIsNextO(isTurn);
 

но когда я проверяю isNextO внутри оператора if, он всегда принимает значение true

    if (isNextO === "yes") {
      console.log("Next is O");
      if (host == 1) {
        console.log("Host is playing");
        return;
      } else if (guest == 1) {
        var isTurn = isNextO === "yes" ? "no" : "yes";
        setIsNextO(isTurn);
        console.log(`Is Next O: ${isTurn} `);
      }
    }
 

даже если значение isNextO равно «нет», приведенный выше оператор main if принимает значение true, и в результате мой хост не может сыграть ни одного хода. В эффекте использования есть некоторые операции с базой данных (базой данных в реальном времени). Ниже приведен полный код файла. Любая помощь будет признательна.

 import React, { useState } from "react";
import Square from "./Square";
import styles from "../styles/Game.module.css";
import firebase from "firebase/app";
import "firebase/database";
const database = firebase.database();

const Board = ({ code, host, getUsers, guest }) => {
  const reference = database.ref(`/game/${code}`);
  const [squares, setSquares] = useState(Array(9).fill(null));
  const [winner, setWinner] = useState("");
  const [isNextO, setIsNextO] = useState("yes");
  const sq = squares;
  const handleClick = (i) => {
    if (calculateWinner(squares) || squares[i]) {
      return;
    }
    if (isNextO === "yes") {
      console.log("Next is O");
      if (host == 1) {
        console.log("Host is playing");
        return;
      } else if (guest == 1) {
        var isTurn = isNextO === "yes" ? "no" : "yes";
        setIsNextO(isTurn);
        console.log(`Is Next O: ${isTurn} `);
      }
    }
    var move = "";
    if (host == 1) {
      move = "X";
    } else if (guest == 1) {
      move = "O";
    }
    // setisNextO(!isNextO);
    // reference
    //   .once("value")
    //   .then((snapshot) => {
    //     const fetchedData = snapshot.val();
    //     const newMovesFetched = fetchedData.moves;
    //     if (host === true) console.log("this is X");
    //     else console.log("this is O");
    //     console.log(`Move: ${move}`);
    //     newMovesFetched.push({
    //       move,
    //       index: i,
    //     });
    //     reference
    //       .update({
    //         moves: newMovesFetched,
    //       })
    //       .then((res) => {
    //         setisNextO(!isNextO);
    //       })
    //       .catch((e) => console.log(e));
    //   })
    //   .catch((e) => console.log(e));
  };

  if (!winner) {
    const winn = calculateWinner(squares);
    if (winn) {
      reference
        .update({
          winner: winn,
        })
        .then(() => {
          setWinner(calculateWinner(squares));
        })
        .catch((e) => console.log(e));
    }
  }

  React.useEffect(() => {
    const change = database.ref(`/game/${code}`).on("value", (snap) => {
      const data = snap.val();
      if (data.guest amp;amp; data.host) {
        const user = {
          guest: data.guest,
          host: data.host,
          winner: data.winner,
        };
        getUsers(user);
      }
      const squares = sq.slice();
      const moves = data.moves;
      for (let i = 0; i < data.moves.length; i  ) {
        const index = moves[i].index;
        const move = moves[i].move;
        squares[index] = move;
        console.log(moves[i]);
      }
      setSquares(squares);
    });
    return () => database.ref(`/game/${code}`).off("value", change);
  }, []);

  const renderSquare = (i) => {
    return <Square value={squares[i]} onClick={() => handleClick(i)} />;
  };

  return (
    <>
      {winner ? (
        <h1>{winner}</h1>
      ) : (
        <div className={styles.board}>
          {renderSquare(0)}
          {renderSquare(1)}
          {renderSquare(2)}
          {renderSquare(3)}
          {renderSquare(4)}
          {renderSquare(5)}
          {renderSquare(6)}
          {renderSquare(7)}
          {renderSquare(8)}
        </div>
      )}
    </>
  );
};

function calculateWinner(squares) {
  const lines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];
  for (let i = 0; i < lines.length; i  ) {
    const [a, b, c] = lines[i];
    if (squares[a] amp;amp; squares[a] === squares[b] amp;amp; squares[a] === squares[c]) {
      return squares[a];
    }
  }
  return null;
}

export default Board;

 

Примечание: Комментируемая часть предназначена для операций с базой данных, основанных на ходах, сыгранных игроками, и комментируется таким образом, чтобы избежать обширных операций чтения-записи во время тестирования кода.

Комментарии:

1. setState вступает в силу только при следующем рендеринге overreacted.io/a-complete-guide-to-useeffect/…

2. @Надя Чибрикова, можете ли вы предложить какое-либо решение? Журнал консоли после setIsNextO корректного отображения состояния

3. Вы можете использовать isTurn вместо isNextO внутри обработчика (после того, как вы позвонили setIsNextO(isTurn); , вы знаете, что в конечном итоге это isNextO будет иметь значение isTurn )

4. Кроме того, у React есть официальный учебник по этой же игре, возможно, вам захочется взглянуть reactjs.org/tutorial/tutorial.html

5. Игра в этом уроке предназначена для локальной игры, но я пытаюсь создать ее с помощью firebase, чтобы два игрока могли играть онлайн