Search code examples
reactjsmultidimensional-arrayreact-hooksminesweeper

React 2d Array of randomly placed components desync


I am trying to create minesweeper in React and have run into a serious problem.

I create a 2d array with bomb and box components called game, and everything works fine, EXCEPT a brand new version of game gets created sometime after the original is created.

I console.log the game before the component renders, and that is a completely different game than what shows up. I have a button that console logs the current game after it renders, and that shows the game on the screen.

    function setBombs() {
        //creates map of board ie. [[false, false, false], [false, true, false], [false, false, false]]
    }
    console.log(game)
    //Prints empty. Good
    setBombs();
    for (let i = 0; i < Map.length; i++) {
        let arr = []
        for (let j = 0; j < Map[i].length; j++) {
            // pushes true(bomb) or false(box) depending if it is going to be a bomb
            // pushes bomb or numbered box component based on a map created before
            arr.push(decideBomb(numBombs, i, j));
        }
        game.push(arr);

        //Prints each version of game. Good
        console.log(game)
    }
    //Prints Correct game. Good
    console.log(game);
    return (
        <div>
            <h1>Minesweeper</h1>
            {/* Ends up being different game. Bad!  goal: make them the same*/}
            <div style={style} className="Grid">{game}</div>
            <button onClick={()=>{console.log(game)}}>clgrid</button>
        </div>
    );

I want the version in the for loop to be the same as the version on the screen.

Should I find a workaround? Or is there a way to prevent a different game from generating?


Solution

  • You should try putting your functions into an useEffect, (like your for loop and your setBombs() call) so that code will be only executed once like so:

    React.useEffect(() => {
        setBombs();
        for (let i = 0; i < Map.length; i++) {
            let arr = []
            for (let j = 0; j < Map[i].length; j++) {
                // pushes true(bomb) or false(box) depending if it is going to be a bomb
                // pushes bomb or numbered box component based on a map created before
                arr.push(decideBomb(numBombs, i, j));
            }
            game.push(arr);
    
            //Prints each version of game. Good
            console.log(game)
        }
    }, [])
    

    Documentation here.