You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Hooks状态重置问题:井字棋无法交替切换X和O如何解决

问题根因分析
  • 状态归属错误:nextChoice(下一个落子方)、firstMove(是否首次落子)属于整个游戏的全局共享状态,不应该定义在单个Square组件内部。每个Square的内部状态完全独立,无法跨组件同步,且组件重挂载时内部状态必然重置,这就是firstMove每次变回true的核心原因。
  • 冗余逻辑冲突:你在Square内部通过useEffect监听data更新nextChoice的逻辑只对当前单个Square生效,其他Square落子不会触发这个更新,导致每个Square首次点击时都会输出X,完全无法实现交替落子。
修复方案

核心思路是将全局状态上移到Board父组件统一管理,Square组件改为无内部状态的受控组件,只负责接收props渲染内容、触发落子回调。

1. 重写Square组件

删除所有内部状态,落子值、点击回调都从props获取:

function Square(props) {
  return (
    <div className="square" style={squareStyle} onClick={props.onClick}>
      {props.value}
    </div>
  );
}

2. 重写Board组件,统一管理全局状态

class Board extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(9).fill(''), // 存储9个格子的落子内容,索引0-8对应从左到右从上到下的格子
      nextPlayer: 'X' // 下一个落子方
    };
  }

  // 处理落子逻辑,接收格子索引作为参数
  handleClick(i) {
    const squares = [...this.state.squares];
    // 格子已经有落子的话直接返回
    if (squares[i] !== '') return;
    squares[i] = this.state.nextPlayer;
    this.setState({
      squares: squares,
      // 切换下一个落子方
      nextPlayer: this.state.nextPlayer === 'X' ? 'O' : 'X'
    });
  }

  // 渲染单个Square的方法
  renderSquare(i) {
    return (
      <Square 
        value={this.state.squares[i]}
        onClick={() => this.handleClick(i)}
      />
    );
  }

  render() {
    return (
      <div style={containerStyle} className="gameBoard">
        <div id="statusArea" className="status" style={instructionsStyle}>
          Next player: <span>{this.state.nextPlayer}</span>
        </div>
        <div id="winnerArea" className="winner" style={instructionsStyle}>
          Winner: <span>None</span>
        </div>
        <button style={buttonStyle} onClick={() => this.setState({squares: Array(9).fill(''), nextPlayer: 'X'})}>Reset</button>
        <div style={boardStyle}>
          <div className="board-row" style={rowStyle}>
            {this.renderSquare(0)}
            {this.renderSquare(1)}
            {this.renderSquare(2)}
          </div>
          <div className="board-row" style={rowStyle}>
            {this.renderSquare(3)}
            {this.renderSquare(4)}
            {this.renderSquare(5)}
          </div>
          <div className="board-row" style={rowStyle}>
            {this.renderSquare(6)}
            {this.renderSquare(7)}
            {this.renderSquare(8)}
          </div>
        </div>
      </div>
    );
  }
}

修改后所有全局状态都在Board组件存储,不会因为Square组件的重挂载被重置,落子方切换逻辑全局同步,完全符合交替落子的需求。

内容的提问来源于stack exchange,提问作者copenndthagen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 17:06:08