Javascript 满足条件时停止更新(反应tic tac toe)

Javascript 满足条件时停止更新(反应tic tac toe),javascript,reactjs,Javascript,Reactjs,我在React中创建了一个快速tic-tac-toe实现,遇到了一个问题,如下所示: 代码如下: 问题: 1.)打印错误的赢家(在用户赢后游戏更改回合) 2.)当用户获胜时,我想显示“赢家:X”,而不是“下一个:X” 为什么失败: 在我的Board.jsx中,我将以下方法传递给我的Square.jsx组件,该组件将更新棋盘状态和玩家回合: const updateBoard = (squareIndex) => { setGameState((prevBoard) =>

我在React中创建了一个快速tic-tac-toe实现,遇到了一个问题,如下所示:

代码如下:

问题

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,用于检查游戏状态或玩家何时更新。这个方法决定胜利者

  // 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]);
//线路板更新事件/操作
useffect(()=>{
const isWinner=()=>{
常量行=[
[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(设i=0;i
所以它之所以打印错误的赢家是因为一旦有人赢了,它仍然会更新玩家回合,然后显示输家

我的问题

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

任何关于解决此问题的最佳方法的建议都将不胜感激

谢谢

您可以尝试以下方法:

  • 添加状态变量以维护状态。将其初始化为
    false
  • 将道具添加到
    Square
    作为禁用。
  • 单击时调用回调基于此:
  • 基于此更新className
    • 使用新创建的状态变量传递属性

  • 您可以在useEffect中更新玩家回合,将
    游戏状态
    作为依赖项
  • 如果isWinner函数返回true,则使用另一种类型的值来声明winner,而不是使用另一种状态
  • const winding\u行=[
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6]
    ];
    函数isWinner(游戏状态){
    for(设i=0;i{
    const[gameState,setGameState]=useState(新数组(9).fill(“”);
    const[playerTurn,setPlayerTurn]=useState(“X”);
    常数更新板=(平方索引)=>{
    setGameState((prevBoard)=>{
    //处理以前设置的值
    如果(前置板[squareIndex]!=“”){
    返回板;
    }
    //否则,更新董事会
    让updatedBoard=[…prevBoard];
    updatedBoard[squareIndex]=播放器翻转;
    返回更新板;
    });
    };
    React.useffect(()=>{
    如果(是赢家(游戏状态)){
    setPlayerTurn(空);
    }否则{
    setPlayerTurn((旋转)=>(旋转==“X”?“O”:“X”);
    }
    },[游戏状态];
    返回(
    {gameState.map((单元格,位置)=>(
    ))}
    下一个:{playerTurn}

    ); }; 导出默认板;
    我已尝试将逻辑简化一点

    链接:

    JS:

    import React,{useffect,useState}来自“React”;
    从“./components/Square/Square”导入正方形;
    从“/Board.module.css”导入样式;
    委员会=()=>{
    const[gameState,setGameState]=useState([]);
    const[playerTurn,setPlayerTurn]=useState(“X”);
    //onMount/todo:当用户重置线路板时
    useffect(()=>{
    const initializeGame=()=>setGameState(新数组(9.fill)(“”);
    初始化名称();
    }, []);
    //董事会更新事件/行动
    useffect(()=>{
    让胜利者=”;
    const isWinner=()=>{
    常量行=[
    [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(设i=0;i{
    如果(游戏状态[squareIndex]!=“”){
    返回;
    }
    让updatedBoard=[…游戏状态];
    updatedBoard[squareIndex]=播放器翻转;
    设置游戏状态(更新板);
    //更新玩家回合
    setPlayerTurn((旋转)=>(旋转==“X”?“O”:“X”);
    };
    返回(
    {gameState.map((单元格,位置)=>(
    ))}
    下一个:{playerTurn}

    ); }; 导出默认板;
    这是可行的,但我想知道在
    isWinner
    中我无法确定获胜者的情况。不过,这是一个很好的解决方案,谢谢。这是因为react将在函数调用(updateBoard)完成后更新useEffect,然后再计算赢家。如果要保留该逻辑,可以创建一个状态
    winner
    ,并仅在赢家时更新playerturn
    const [gameFinished, setFinished] = useState(false);
    
    const clickHandler = () => {
      if (!isDisabled) updateBoard(boardPosition);
    };
    
    if (isDisabled) {
      classes.push("disabled");
    }
    
    isDisabled={gameFinished}
    
    const WINNING_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]
    ];
    
    function isWinner(gameState) {
      for (let i = 0; i < WINNING_LINES.length; i++) {
        const [a, b, c] = WINNING_LINES[i];
        if (
          gameState[a] &&
          gameState[a] === gameState[b] &&
          gameState[a] === gameState[c]
        ) {
          return true;
        }
      }
      return false;
    };
    
    const Board = () => {
      const [gameState, setGameState] = useState(new Array(9).fill(""));
      const [playerTurn, setPlayerTurn] = useState("X");
    
    
      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;
        });
      };
    
       React.useEffect(() => {
        if (isWinner(gameState)) {
          setPlayerTurn(null);
        } else {
          setPlayerTurn((turn) => (turn === "X" ? "O" : "X"));
        }
      }, [gameState]);
    
      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;
    
    
    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;