React开发井字棋:获胜检测函数无法识别数组值问题求助
井字棋获胜检测失效的问题修复
几个关键问题点
- 获胜检查函数提前退出:
checkWin里的第一个if,只要当前遍历的赢法组合第一个格子是空,就直接return退出函数了——这会导致比如玩家在最后一行连成三个时,前面的赢法组合里有空格子,函数直接跑路,根本不会检查到后面的获胜情况。 - 相等判断逻辑错误:
board[a] == board[b] == board[c]这种写法在JS里完全不成立,先判断前两个对象是否相等(对象比的是引用,永远不等),然后拿布尔值和第三个对象对比,结果永远是false,等于白判断。 - State更新异步坑:
setBoard是异步操作,你刚改完就调用checkWin,拿到的还是旧的board状态,自然检查不到最新的落子。 - 回合切换时机错误:你先切换回合再检查获胜,导致控制台打印的获胜玩家是下一个回合的人,完全搞反了。
- 对象属性不统一:初始化的board元素是
{num: i, value:''},落子时改成{id: cell.id, value: currentTurn},属性名混乱,虽然暂时不影响取value,但容易引发其他潜在bug。
修复后的代码
App.js
import logo from './logo.svg'; import './App.css'; import { useState, useEffect } from 'react'; import Board from './components/Board'; function App() { const [board, setBoard] = useState([]); const [currentTurn, setCurrentTurn] = useState(''); const [gameOver, setGameOver] = useState(false); function checkWin() { if (gameOver) return; // 游戏结束后不再检查 // 修正原代码错误:[2,4,8]改为[2,5,8],这才是纵向第三列的正确索引 const winConditions = [ [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6], [0, 1, 2], [3, 4, 5], [6, 7, 8] ]; for (let j = 0; j < winConditions.length; j++) { const [a, b, c] = winConditions[j]; const valA = board[a]?.value; const valB = board[b]?.value; const valC = board[c]?.value; // 有空格子就跳过当前赢法,不直接退出函数 if (!valA || !valB || !valC) continue; // 正确判断三个格子的value是否相等 if (valA === valB && valB === valC) { setGameOver(true); console.log(`Game Over! ${currentTurn} has won`); return; // 找到获胜条件后直接退出,无需继续检查 } } } function populateObject() { // 用Array.from简化初始化代码 const mockarray = Array.from({length:9}, (_,i) => ({num: i, value: ''})); setBoard(mockarray); setCurrentTurn('x'); setGameOver(false); // 重置游戏结束状态 } function fillCell(event) { if (gameOver) return; // 游戏结束后禁止落子 const cellIndex = parseInt(event.target.id); if (board[cellIndex].value !== '') return; // 已有棋子的格子禁止点击 // 遵循React immutable原则,创建新数组更新state const newBoard = [...board]; newBoard[cellIndex] = {num: cellIndex, value: currentTurn}; setBoard(newBoard); } // 监听board变化,确保用最新状态检查获胜 useEffect(() => { if (board.length === 0) return; checkWin(); // 仅当未获胜且不是初始化状态时,才切换回合 if (!gameOver && board.some(cell => cell.value !== '')) { setCurrentTurn(prev => prev === 'x' ? 'o' : 'x'); } }, [board, gameOver]); useEffect(() => { populateObject(); }, []); return ( <div className="App"> <Board fillFunction={fillCell} currentTurn={currentTurn} valuearray={board} /> <button onClick={populateObject}>Reset</button> </div> ); } export default App;
Board.js(补全key属性,优化渲染逻辑)
import '../stylesheets/board.css' function Board({valuearray, currentTurn, fillFunction}) { const insertSymbol = (value) => { switch(value) { case 'x': return <i className='fa solid fa-x'></i>; case 'o' : return <i className='fa solid fa-o'></i>; default: return ''; } } return( <div className="board-section"> <div className='turn-header'> <h4>It is currently {currentTurn}'s turn</h4> </div> <div className='board'> {valuearray.map(v => ( <div className="cell" key={v.num} // React列表必须添加key属性 id={v.num} onClick={fillFunction} > {insertSymbol(v.value)} </div> ))} </div> </div> ) } export default Board;
额外细节说明
- 修复了原
winConditions中的错误索引,确保所有赢法组合正确 - 添加了游戏结束后禁止落子、已有棋子格子禁止点击的逻辑
- 用
Array.from简化了board初始化代码,更简洁 - 为Board组件的列表项添加
key属性,消除React渲染警告
内容的提问来源于stack exchange,提问作者Kevin H
相关产品推荐
相关产品推荐

