首页 > 解决方案 > 满足条件时停止更新(React tic-tac-toe)

问题描述

我正在 React 中创建一个快速井字游戏实现,并遇到了一个问题,见此处: 在此处输入图像描述

这是代码:

https://codesandbox.io/s/cold-grass-yr6mn?file=/src/container/Board.jsx

问题

1.)它打印错误的获胜者(用户获胜后游戏改变回合)

2.)当用户获胜时,我想显示“获胜者:X”,而不是“下一个:X”。

为什么失败

在我的Board.jsx中,我将以下方法传递给我的 Square.jsx 组件,它会更新棋盘状态和玩家回合:

  const updateBoard = (squareIndex) => {
    setGameState((prevBoard) => {
      // handle previously set value
      if (prevBoard[squareIndex] !== "") {
        return prevBoard;
      }
      // otherwise update the board
      let updatedBoard = [...prevBoard];
      updatedBoard[squareIndex] = playerTurn;
      return updatedBoard;
    });

    // update player turn
    setPlayerTurn((turn) => (turn === "X" ? "O" : "X"));
  };

在同一个文件中,我有一个 useEffect 来检查 gameState 或玩家何时更新。这种方法决定了获胜者。

  // board update events/actions
  useEffect(() => {
    const isWinner = () => {
      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 (
          gameState[a] &&
          gameState[a] === gameState[b] &&
          gameState[a] === gameState[c]
        ) {
          return true;
        }
      }
      return false;
    };

    if (isWinner()) {
      alert(`${playerTurn} is the winner.`);
      return;
    }
  }, [gameState, playerTurn]);

所以它打印错误获胜者的原因是因为一旦有人获胜,它仍然会更新玩家回合,然后会显示失败的玩家。

我的问题

处理更新玩家回合的最佳方法是什么?如果我在我的 useEffect 中设置播放器,我将得到一个无限渲染循环。我可以想出一些破解方法来修复它,比如打印与当前玩家轮到赢家相反的东西。但这似乎并不理想。

任何有关解决此修复的最佳方法的建议都值得赞赏。

谢谢!

标签: javascriptreactjs

解决方案


我试图稍微简化一下逻辑。

链接:https ://codesandbox.io/s/elastic-moon-bcps0?file=/src/container/Board.jsx:0-1829

JS:

import React, { useEffect, useState } from "react";
import Square from "../components/Square/Square";

import styles from "./Board.module.css";

const Board = () => {
  const [gameState, setGameState] = useState([]);
  const [playerTurn, setPlayerTurn] = useState("X");

  // onMount / todo: when user resets board
  useEffect(() => {
    const initializeGame = () => setGameState(new Array(9).fill(""));
    initializeGame();
  }, []);

  // board update events/actions
  useEffect(() => {
    let winner = "";
    const isWinner = () => {
      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 (
          gameState[a] &&
          gameState[a] === gameState[b] &&
          gameState[a] === gameState[c]
        ) {
          winner = gameState[a];
          return true;
        }
      }
      return false;
    };

    if (isWinner()) {
      alert(`${winner} is the winner.`);
    }
  }, [gameState]);

  const updateBoard = (squareIndex) => {
    if (gameState[squareIndex] !== "") {
      return;
    }

    let updatedBoard = [...gameState];
    updatedBoard[squareIndex] = playerTurn;

    setGameState(updatedBoard);
    // update player turn
    setPlayerTurn((turn) => (turn === "X" ? "O" : "X"));
  };

  return (
    <>
      <main className={styles.board}>
        {gameState.map((cell, position) => (
          <Square
            boardPosition={position}
            displayValue={cell}
            updateBoard={updateBoard}
            key={position}
          />
        ))}
      </main>
      <div>
        <p>Next: {playerTurn}</p>
      </div>
    </>
  );
};

export default Board;

推荐阅读