react教程-井字棋案例扩展01

井字棋案例可以在 react 官网上按步骤去逐步实现,但是官网上的教程还有一部分扩展是未实现的,有兴趣的可以尝试一下

案例代码地址:https://gitee.com/aolie/test_react

在游戏历史记录列表显示每一步棋的坐标,格式为 (列号, 行号)

这个案例是实现这个需求 ,其实这个需求难度不大,只要注意一点就行,那就是,this.setState(),这个方法,在改变 state 中的数据之后,是不会立即生效的,如果需要立即调用这个数据的话,需要在内部写一个异步的回调函数去使用 更新后的数据

1、在点击单元格的时候,需要记录下当前点击单元格的坐标,但是需要注意的是,当我回到第一步还未开始的状态时,此时需要设置一个默认坐标,不然和步骤对不上,我默认给的是[0,0]

export default class Game extends Component {
  constructor(props) {
    super(props);
    this.state = {
      history: [{ squares: Array(9).fill(null) }],
      xIsNext: true,
      setNumber: 0,
      coordinate: [[0, 0]] //初始位置默认为坐标[0,0]
    };
  }
}

2、在 Game.js  顶层父ji组件中,我们需要先记录所有单元格的坐标,以便与在点击的时候,添加到数组中,与历史记录步骤匹配。点击单元格的时候,会将该单元格的排序传递进来,根据排序找到当前点击单元格坐标,且将点击的坐标添加到历史坐标记录数组中

  // 记录历史记录坐标
  historyCoordinate(i) {
    let Coordinate = [
      [1, 1],
      [1, 2],
      [1, 3],
      [2, 1],
      [2, 2],
      [2, 3],
      [3, 1],
      [3, 2],
      [3, 3]
    ];
    this.setState({
      coordinate: [...this.state.coordinate, Coordinate[i]]
    });
  }

3、单元格点击事件扩展

需要分为两种情况,

第一种是,直接点击单元格,记录历史坐标。

第二种是,先点击单元格,记录历史坐标,然后点击历史记录,查看之前的游戏状态,且在此时再次点击单元格,改变游戏状态的同时记录新的游戏记录和点击坐标

// 顶层判断单元格点击事件
  handleClick(i) {
    // const history = this.state.history;
    // 创建一个副本,避免改动原来的历史记录数据
    // 这个副本保存的是之前的原始数据从头开始的到现在的最后一步,如果是第一次点击,其实就是history.length 如果是查看历史记录,那就是 当前查看步数
    const history = this.state.history.slice(0, this.state.setNumber + 1);
    // console.log(history);

    // 获取当前点击的步骤,如果是第一次点击单元格,那么setNumber和length-1一样,如果是查看历史记录,那么就是当前查看的步数
    const current = history[history.length - 1];

    // 以上两步是属于取数据,这一步得到一个当前点击之后的 单元格状态副本,之所以用副本,是为了不改变历史数据
    const squares = current.squares.slice();
    if (this.calculateWinner(squares) || squares[i]) {
      return;
    }

    
    // 这一步就是点击历史记录之后,需要将当前的历史记录与历史坐标对应,获取初始状态到当前记录的历史坐标
    // 这一步是和上面的存取数据类似,也是用副本操作数据,当我在点击历史记录的时候,也是需要改变当前历史坐标的数据的,避免直接改变 state 中的数据,二是通过setState 去改变数据
    const coordinate_1 = this.state.coordinate.slice(
      0,
      this.state.setNumber + 1
    );

    squares[i] = this.state.xIsNext ? "X" : "O";
    this.setState(
      {
        history: history.concat([{ squares: squares }]),
        xIsNext: !this.state.xIsNext,
        setNumber: history.length,
        coordinate: coordinate_1
      },
      state => {
        // 这一步是关键点,当我点击之后,通过上面的 setState 重新改变了当前的历史坐标记录数组
        // 但是并没有立即生效,如果我把这一步操作放在 stestate 外部,那么扩展运算符得到的还是改变之前的坐标数组
        this.historyCoordinate(i);
      }
    );
    console.log(this.state.coordinate);
  }

4、render 渲染

const moves = history.map((step, index) => {
      const desc = index ? "Go to move #" + index : "Go to game start";
      return (
        <li key={index}>
          <button
            onClick={() => {
              this.jump(index);
            }}
          >
            {`${desc}+${this.state.coordinate[index]}`}
          </button>
        </li>
      );

return (
      <div className="game">
        <div className="game-board">
          <Board
            squares={current.squares}
            onClick={i => {
              this.handleClick(i);
            }}
          />
        </div>
        <div className="game-info">
          <div>{status}</div>
          <ol>{moves}</ol>
          {/* {this.historyMove} */}
        </div>
      </div>
    );

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值