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

React Native开发井字棋时出现Maximum call stack size exceeded错误如何解决?

问题根因

你遇到的Maximum call stack size exceeded报错是典型的无限递归导致的调用栈溢出,触发逻辑链如下:

  • 电脑回合触发BotMove随机生成行、列坐标
  • 调用checkTilesOwner判断坐标是否被占用,如果被占用会再次调用BotMove重新随机坐标
  • 当棋盘剩余空格很少、甚至没有空格时,随机坐标连续命中已占用格子的概率大幅上升,无限递归调用BotMove和checkTilesOwner,最终撑爆调用栈

另外你的代码里还有一个隐藏bug:setState是异步方法,调用后不会立即更新this.state的值,你在onTilePress里调用setState后直接读取this.state判断输赢、平局,拿到的都是更新前的旧值,会导致胜负判断逻辑出错。

修复方案

1. 删掉多余递归逻辑,重写BotMove方法

不要用递归碰运气找空格子,先遍历棋盘收集所有空坐标,没有空坐标直接返回,有就随机选一个直接落子,完全不需要checkTilesOwner方法:

BotMove = () => {
  // 收集所有空格子的坐标
  const emptyTiles = [];
  this.state.gameState.forEach((row, rowIdx) => {
    row.forEach((val, colIdx) => {
      if (val === 0) {
        emptyTiles.push([rowIdx, colIdx]);
      }
    })
  })
  // 没有空格子直接返回,不需要再落子
  if (emptyTiles.length === 0) return;
  // 随机选一个空坐标直接落子
  const [randRow, randCol] = emptyTiles[Math.floor(Math.random() * emptyTiles.length)];
  this.onTilePress(randRow, randCol);
}

2. 删除冗余的checkTilesOwner方法

这个方法的逻辑完全可以被上面重写的BotMove替代,直接删除即可。同时注意人类玩家点击格子的逻辑不需要走这个方法,直接调用onTilePress就行,onTilePress本身已经做了格子是否为空的判断。

3. 修复onTilePress里异步setState的问题

把后续胜负判断、切换回合的逻辑放到setState的回调里,确保判断时用的是已经更新后的状态:

onTilePress = (row, col) => {
  // 原有格子非空判断保留
  const value = this.state.gameState[row][col];
  if (value !== 0) return;

  const currentPlayer = this.state.currentPlayer;
  // 生成新的棋盘状态
  const newGameState = this.state.gameState.map(row => [...row]);
  newGameState[row][col] = currentPlayer;
  const nextPlayer = currentPlayer === 1 ? -1 : 1;

  // 一次性更新state,后续逻辑放到回调里保证state已更新
  this.setState({
    gameState: newGameState,
    currentPlayer: nextPlayer
  }, () => {
    const winner = this.getWinner();
    const checkDraw = this.checkTie();
    if (winner === 1) {
      Alert.alert("Player 1 has won!");
      this.initializeGame();
      return;
    }
    if (winner === -1) {
      Alert.alert("Bot has won!");
      this.initializeGame();
      return;
    }
    if (checkDraw === 9) {
      Alert.alert("It's a draw!");
      this.initializeGame();
      return;
    }

    // 处理回合切换提示
    if (nextPlayer === 1) {
      Alert.alert("Player 1's turn!");
    } else {
      Alert.alert("Bot's turn!");
      this.BotMove();
    }
  })
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 11:15:02