我如何在另一个调用this.setState()的函数内部的函数中访问组件的状态?

问题描述 投票:2回答:3

我正在构建我的第一个React应用,并且遇到了这种情况,在这种情况下,我必须在一个方法中两次调用this.setState()。这些调用之一也是在从该方法调用的嵌套函数中进行的。

就我而言,我正在开发扫雷游戏,而我试图实现的目标是找出玩家在正确标记所有地雷之后是否真正获胜。当设置标志超过包含地雷的每个单元时,玩家将获胜,因此您无法单击它。为此,我创建了一个名为checkIfWin()的方法,该方法执行以下操作:

  1. 将板子数据信息(每个单元格及其属性)存储在阵列中,并在计数器中存储剩余地雷的数量。都从组件状态中提取两个变量,分别称为dataminesLeft
  2. 如果还有0个地雷(用户标记的单元格数量与游戏中的地雷相同),则可以比较两个数组(minesArray包含板中每个地雷位置,flagsArray包含每个地雷位置)标志位置)
  3. 如果数组包含相同的信息(标志覆盖着每个地雷),您将获胜。如果阵列不同,请继续播放。

此函数从两个不同的地方调用

  1. [玩家单击最后一个不包含地雷的单元之后,每个包含标志的图块均已正确标记
  2. [玩家标记一个单元格后,棋盘上剩余的地雷为0在第一种情况下,它工作正常没有问题。我检查状态中的[[minesLeft是否=== 0,如果是,则调用方法checkIfWin()。由于minesLeft仅在标记一个单元格后才减少,而不是单击一个单元格,因此这里没有问题。
但是当玩家在一个单元格上标记后,我无法设法找到一个解决方案来声明玩家是否赢得了比赛。这是我的flag()逻辑:

    [检查是否覆盖了它的瓷砖(尚未被单击),以及玩家是否尚未赢(为了防止游戏结束后单击瓷砖)
  1. 如果覆盖并标记了图块,请取消标记并更新计数器。
  2. 如果覆盖并没有标记图块,则用标记覆盖它并减少
  3. minesLeft
计数器。 [
  • minesLeft为1并且Player标记一个新单元格时,minesLleft现在为0,所以这是我必须检查获胜的时间。
  • 现在这是
  • 我想检查玩家是否获胜的地方
  • 为此,我必须调用this.setState()以将新标志的位置更新为[[flagsArray板,然后调用checkIfWin()-也从此方法中提取存储在state中的值。这导致对batch up before executing fully的this.setState()调用,因此当我尝试比较checkIfWin()中的minesLeft === 0时,存储在state中的值是state在最后一个值之前的值标记(从1代替0),它没有更新,因为React为this.setState()调用堆积了逻辑。在JusticeMba article on medium上也提到过

    React可以将多个setState()调用批处理为单个更新以提高性能。

    所以

    我想知道什么

    (很抱歉,问题的长度)是,是否有什么办法可以做到这一点?我实际上将此标记方法绑定为Board的render()内部组件的右键单击处理程序。代码如下。我不在乎您是否知道某些代码或伪代码解决方案。我会把两者都考虑进去,因为我似乎没有为此找到合适的解决方法。

    代码:

    Inside Board.js render()

    render() { const board = this.renderBoard(this.state.boardData); return ( <div className={classes.board}> <div className={classes.gameInfo}> <h1> {this.state.gameStatus} </h1> <span className={classes.info}> Mines remaining: {this.state.mineCount} </span> </div> {board} //This is a Board component that holds Tiles to which the rightClickHandler() is binded as a prop </div>

    用于管理Tiles标记的rightClickHandler():

    rightClickHandler(event, x, y) {
        event.preventDefault();  // prevents default behaviour such as right click
        const clickedTile = { ...this.state.boardData[x][y] }
    
         //ommit if revealed and if  game is ended
        if (!clickedTile.isRevealed && !(this.state.gameStatus === "YOU WON!")) {
    
            let minesLeft = this.state.mineCount;
    
            //if not revealed it can be flagged or not
            if (clickedTile.isFlagged) {
    
                //if flagged, unflag it
                clickedTile.isFlagged = false;
                minesLeft++;
            } else {
    
                //if not flagged, flag it
                clickedTile.isFlagged = true;
                minesLeft--;
            }
    
            //Update the state with new tile and check game status
            const updatedData = [...this.state.boardData];
            updatedData[x][y] = { ...clickedTile };
    
            this.setState({
                boardData: updatedData,
                mineCount: minesLeft,
            });
    
        //THIS IS WHERE I WOULD LIKE TO checkIfWin() 
    
        }
    

    最后,checkIfWin():

    //Check game progress and returns a boolean: true if win, false if not.  
    checkIfWin() {
    
        //No need to create a new array, I'll just reference the one inside state
        const data = this.state.boardData;
        const minesLeft = this.state.mineCount;
    
        //If  flagged as many tiles as mines were initially
        if (minesLeft === 0) {
    
            //get mines as an array of positions
            const mineArray = this.getMines(data);
    
            //get flags as array of positions
            const flagArray = this.getFlags(data);
    
            if (JSON.stringify(mineArray) === JSON.stringify(flagArray)) {
    
                //if both arrays are equal, game is won
                return true;
            }
    
        } else {
    
            //if more than 0 mines are left return false
            return false;
        }
    }
    

    TL; DR:我正在尝试使用过时状态访问组件属性的值,该状态应该从render()内JSX组件的单击处理程序中的先前this.setState()调用进行更新。 >

    很抱歉,篇幅太长,我希望这是可以理解的。 

    我正在构建我的第一个React应用,并且遇到了这种情况,在这种情况下,我必须在一个方法中两次调用this.setState()。这些调用之一是在从方法...

    javascript reactjs react-native logic pseudocode
    3个回答
    1
    投票
    rightClickHandler(event, x, y) { // Rest of your code... // Pass a callback to your setState this.setState({ boardData: updatedData, mineCount: minesLeft, }, this.checkIfWin); }

    1
    投票

    0
    投票
    © www.soinside.com 2019 - 2024. All rights reserved.