【问题标题】:Trying to change game move when clicked on a button but it doesn't work单击按钮时尝试更改游戏动作但不起作用
【发布时间】:2021-04-12 21:43:24
【问题描述】:

我正在 react.js 中构建一个棋盘游戏,现在我正在尝试添加一个允许用户快速浏览游戏的功能。我以为我搞定了,但它不起作用。我检查了我的对象是否是不可变的(它们应该是),我还检查了是否调用了返回游戏步骤的函数,也没有任何问题。我不知道为什么它不起作用。我该如何解决?

这是带有游戏数据的构造函数:

constructor(props) {
        super(props);
        this.state = {
            // The Game Data Comes Here
            history: [{
                squares: [
                    Array(8).fill(null),
                    Array(8).fill(null),
                    Array(8).fill(null),
                    [null,null,null,'black','white',null,null,null],
                    [null,null,null,'white','black',null,null,null],
                    Array(8).fill(null),
                    Array(8).fill(null),
                    Array(8).fill(null)
                ]
            }],
            stepNumber: 0,
            blackIsNext: true,
            winner: null
        }
    }

这里是我渲染的地方:

render() {
        // datas that will be rendered regularly come here
        const history = this.state.history
        const current = history[this.state.stepNumber]
        const moves = history.map((_, move) => {
            const desc = move ? 'Go to move #' + move : 'Go to game start';
            return (
              <li key={move}>
                <button onClick={() => this.jumpTo(move)}>{desc}</button>
              </li>
            );
        });

        // Return the game scene here
        return (
            <div className="master-container">
                <GameBoard squares={current.squares} onClick={(row,col) => {
                    if (!this.state.winner) {
                        const elems = this.checkElementsAround(this.checkEmptySpaces())
                        for (let el=0;el<elems.length;el++) {
                            const turning = this.checkTurningStones(elems[el].directions, this.state.blackIsNext)
                            if (turning.length !== 0) {
                                turning.unshift([row,col])
                                if (row === elems[el].coordinates[0] && col === elems[el].coordinates[1]) {
                                    this.handleMove(turning)
                                    this.setWinnerAndTurn()
                                    // Debug
                                    //console.log(history.length)
                                    console.log(moves)
                                    break
                                }
                            }                        
                        }
                    }
                }}/>
                <div>{(!this.state.winner) ? "Player Turn: " + `${(this.state.blackIsNext) ? 'Black' : 'White'}` : 'WINNER: ' + this.state.winner}</div>
                <div>{(this.state.winner) ? moves : null}</div>
            </div>
        )
    }

有些函数我不会放,因为它们所做的几乎是无关紧要的,它们不会改变数据。而且我也不会放置 setWinnerAndTurn 函数,因为它只在游戏结束或切换玩家回合时定义游戏获胜者,但这里的问题必须与我处理 history 数据的方式有关。

处理移动和跳转到游戏另一步骤的函数

handleMove(cords) {
        // You'll return if the game is already over or the value of the square is NOT null
        if (this.state.winner) {
            return
        }
        // Handle the recently made move here
        const history = this.state.history.slice(0, this.state.stepNumber + 1);
        const current = history[this.state.stepNumber];
        const squares = current.squares.slice()

        // You'll handle the click here
        for (var i=0;i<cords.length;i++) {
            squares[cords[i][0]][cords[i][1]] = (this.state.blackIsNext) ? "black" : "white"
        }


        this.setState({
            history: history.concat([{squares: squares}]),
            stepNumber: history.length,
        });
}

jumpTo(step) {
        this.setState({
          stepNumber: step,
          blackIsNext: (step % 2) === 0,
        });
    }

如果您认为缺少解决问题的方法,请告诉我。

【问题讨论】:

  • 乍一看,我认为您的问题是unshift,这是一个变异操作。编辑:这里还有一个突变:squares[cords[i][0]][cords[i][1]] =
  • 我想我找到了问题所在。通过调试,我意识到历史数组中的所有元素都被更新了
  • 是的,但不会存储,只是暂时存储在那里。
  • 好吧,正方形的元素可以被改变,因为它们将作为新的正方形值传递
  • 这是一个突变,因为squares 是来自状态的数组的浅拷贝。 squares 数组是新的,但 squares 内部的数组是相同的。您正在处理深度嵌套的数据,因此很难update without mutation。老实说,我会推荐一个像 immer 这样的助手。

标签: javascript reactjs setstate


【解决方案1】:

此行中的赋值操作是组件状态的突变。

squares[cords[i][0]][cords[i][1]] = (this.state.blackIsNext) ? "black" : "white"

这是一个突变,因为squares 是来自this.state 的数组的浅表副本。 squares 数组是新的,但是正方形里面的数组是一样的。

您正在处理深度嵌套的数据,因此很难update without mutation。老实说,我会推荐一个像 immer 这样的助手,它可以让你在草稿状态下进行赋值操作。

如果没有帮助程序,您必须映射 squares 并修改内部数组(至少是元素更改的数组)。我认为这是正确的,但请仔细检查我没有混淆行和列。

// Handle the recently made move here
const history = this.state.history.slice(0, this.state.stepNumber + 1);
const current = history[this.state.stepNumber];

// Apply changes to every square
const color = this.state.blackIsNext ? "black" : "white";
const nextSquares = current.squares.map((row, y) =>
  row.map((square, x) =>
    // find if this [x,y] is in the cords array and replace it if it is
    cords.some((cord) => cord[0] === x && cord[1] === y) ? color : square
  )
);

// Update the state
this.setState({
  history: history.concat({ squares: nextSquares }),
  stepNumber: history.length
});

【讨论】:

  • 它有所帮助,但我现在仍有问题。历史数组来自后面。在concat 的帮助下将元素推送到历史数组后,它会显示第一个而不是前两个。并且一直这样下去。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-04
  • 2014-03-24
  • 2021-11-06
  • 2020-02-13
  • 2018-10-30
  • 2022-01-26
相关资源
最近更新 更多