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

标签 javascript reactjs react-native logic pseudocode

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

以我为例,我正在构建一个扫雷游戏,而我想要实现的目标是找出玩家在正确标记所有地雷之后是否真的赢了。在包含地雷的每个单元格上设置标志时,玩家会获胜,因此您无法单击它。
为此,我创建了一个名为checkIfWin()的方法,该方法执行以下操作:


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


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


玩家单击最后一个不包含地雷的单元并正确标记每个包含标记的图块后
玩家标记一个单元格后,要掩盖的剩余地雷为0
在第一种情况下,它工作正常没有问题。我检查minesLeft的状态是否为=== 0,如果是,则调用方法checkIfWin()。由于minesLeft仅在标记一个单元格后才减少,而不是单击一个单元格,因此这里没有问题。


但是当玩家在一个单元格上进行标记后,我无法找到一种解决方案来声明玩家是否赢得了比赛。这是我的flag()逻辑:


检查是否覆盖了该图块(尚未单击),以及玩家是否尚未赢(以防止游戏结束后单击图块)
如果覆盖并标记了图块,请取消标记并更新计数器。
如果瓷砖被覆盖,并且没有被标记,则用旗帜覆盖它,并减少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()内部组件的右键单击处理程序。代码如下。我不在乎您是否知道某些代码或伪代码解决方案。我会把两者都考虑进去,因为我似乎没有找到合适的解决方案。

码:

内部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()调用进行更新

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

最佳答案

假设我理解正确,则可以将checkIfWin作为回调传递给setState

rightClickHandler(event, x, y) {
    // Rest of your code...

    // Pass a callback to your setState
    this.setState({
        boardData: updatedData,
        mineCount: minesLeft,
    }, this.checkIfWin);

}

关于javascript - 如何在另一个调用this.setState()的函数内部的函数中访问组件的状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52107332/

相关文章:

reactjs - Flatlist onEndReached 无限循环

javascript - reactjs App.test.js 错误

javascript - 限制 Reducer 的结果

javascript - pubnub历史API调用总是返回timetoken

javascript - knockout 选择绑定(bind),在选项添加晚时不记住值

javascript - 使用 LESSPHP 减少 javascript 评估错误

javascript - 找到什么 javascript 改变了 DOM?

javascript - 根据 redux 状态中的另一个值解构对象

javascript - 如何将值传递给此 react 组件

menu - 带有路线或导航的 react-native-side-menu 的完整工作示例