React井字棋:点击获胜棋子后如何同步设置获胜状态?
井字棋获胜状态即时更新解决方案
问题根源
- 闭包导致状态陈旧:
newStatuses声明在组件顶层,每次组件渲染都会重新生成,但handleClick引用的是旧变量实例,状态更新不同步。 - 用旧状态判断获胜:调用
handleWinning(status)时,status还是点击前的旧状态,刚下的棋子状态没被纳入判断。 - 获胜状态未触发重渲染:修改
newStatuses后没有再次调用setStatus,界面无法感知获胜状态变化。
修改后的代码
function Board() { const [nextMoveX, setNextMoveX] = useState(true); const [status, setStatus] = useState(Array(9).fill(empty)) function handleClick(i) { // 每次点击基于当前状态创建新数组,避免闭包问题 const newStatuses = status.slice(); // 设置当前点击棋子的状态 const currentMove = nextMoveX ? clickedX : clickedZero; newStatuses[i] = currentMove; // 检查获胜线并修改状态 const winningLines = [ [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 (const line of winningLines) { const [a, b, c] = line; if (newStatuses[a] === currentMove && newStatuses[b] === currentMove && newStatuses[c] === currentMove) { const winStatus = nextMoveX ? xWin : zeroWin; newStatuses[a] = winStatus; newStatuses[b] = winStatus; newStatuses[c] = winStatus; break; // 找到获胜线后停止检查 } } // 统一更新状态,一次完成棋子+获胜状态同步 setStatus(newStatuses); setNextMoveX(!nextMoveX); } return ( <div className={styles.mainContainer}> <Button classTitle={status[0]} onClick={() => handleClick(0)}/> {/* 省略中间6个Button组件 */} <Button classTitle={status[8]} onClick={() => handleClick(8)}/> </div> ); };
关键优化点
- 将
newStatuses移至handleClick内部,确保每次操作的都是当前最新状态的副本。 - 用刚修改后的新状态数组判断获胜,避免旧状态导致的判断失效。
- 找到获胜线后直接修改新状态数组,通过一次
setStatus完成所有状态更新,确保界面即时渲染获胜样式。
内容的提问来源于stack exchange,提问作者tomvas
相关产品推荐
相关产品推荐

