1

I'm attempting to build a Minesweeper game as practice using React. I have a main Minesweeper.js file with all of the functionality.

export class Tile {
  constructor(board, pos) {
      this.board = board;
      this.pos = pos;
      this.bombed = false;
      this.explored = false;
      this.flagged = false;
  }

  adjacentBombCount() {
    let bombCount = 0;
    this.neighbors().forEach(neighbor => {
      if (neighbor.bombed) {
        bombCount++;
      }
    });
    return bombCount;
  }

  explore() {
    if (this.flagged || this.explored) {
      return this;
    }

    this.explored = true;
    if (!this.bombed && this.adjacentBombCount() === 0) {
      this.neighbors().forEach(tile => {
        tile.explore();
      });
    }

  }

  neighbors() {
    const adjacentCoords = [];
    Tile.DELTAS.forEach(delta => {
      const newPos = [delta[0] + this.pos[0], delta[1] + this.pos[1]];
      if (this.board.onBoard(newPos)) {
        adjacentCoords.push(newPos);
      }
    });

    return adjacentCoords.map(coord => this.board.grid[coord[0]][coord[1]]);
  }

  plantBomb() {
    this.bombed = true;
  }

  toggleFlag() {
    if (!this.explored) {
      this.flagged = !this.flagged;
      return true;
    }

    return false;
  }
}

Tile.DELTAS = [[-1, -1], [-1,  0], [-1,  1], [ 0, -1],
             [ 0,  1], [ 1, -1], [ 1,  0], [ 1,  1]];

export class Board {
  constructor(gridSize, numBombs) {
    this.gridSize = gridSize;
    this.grid = [];
    this.numBombs = numBombs;
    this.generateBoard();
    this.plantBombs();
  }

  generateBoard() {
    for (let i = 0; i < this.gridSize; i++) {
      this.grid.push([]);
      for (let j = 0; j < this.gridSize; j++) {
        const tile = new Tile(this, [i, j]);
        this.grid[i].push(tile);
      }
    }
  }

  onBoard(pos) {
    return (
      pos[0] >= 0 && pos[0] < this.gridSize &&
        pos[1] >= 0 && pos[1] < this.gridSize
    );
  }

  plantBombs() {
    let totalPlantedBombs = 0;
    while (totalPlantedBombs < this.numBombs) {
      const row = Math.floor(Math.random() * (this.gridSize - 1));
      const col = Math.floor(Math.random() * (this.gridSize - 1));

      let tile = this.grid[row][col];
      if (!tile.bombed) {
        tile.plantBomb();
        totalPlantedBombs++;
      }
    }
  }

  lost() {
    let lost = false;
    this.grid.forEach(row => {
      row.forEach(tile => {
        if (tile.bombed && tile.explored) {
          lost = true;
        }
      });
    });
    return lost;
  }

  won() {
    let won = true;
    this.grid.forEach(row => {
      row.forEach(tile => {
        if (tile.flagged === tile.revealed || tile.flagged !== tile.bombed) {
          won = false;
        }
      });
    });
    return won;
  }
}

Then I have three React components: Board.jsx

import React from "react";
import Tile from "./tile";

class Board extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        return(
            <div>
                {this.props.board.grid.map((row, idx) => {
                    return (<div key={idx}>
                       {row.map((tile, idx) => {
                        return (
                            <div key={idx}>
                                <Tile
                                tile={tile}
                                updateGame={this.props.updateGame}/>
                            </div>
                        )
                       })} 
                    </div>)
                })}
            </div>
        )
    }
}

export default Board;

Tile.jsx

import React from "react";

class Tile extends React.Component {
    constructor(props) {
        super(props)
        this.checkState = this.checkState.bind(this)
    }

    checkState() {
        console.log(this)
        if (this.props.tile.bombed) {
            return "💣"
        } else if (this.props.tile.explored) {
            return (this.props.tile.adjacentBombCount())
        } else if (this.props.tile.flagged) {
            return "⚐"
        } else {
            return ""
        }
    }

    render() {
        return(
            <div>{this.checkState()}</div>
        )
    }
}

export default Tile;

and finally a Game.jsx

import React from "react";
import * as Minesweeper from "../minesweeper"
import Board from "./board";

class Game extends React.Component {
    constructor(props) {
        super(props);
        let board = new Minesweeper.Board(10, 5)
        this.state = {
            board: board
        }
    this.updateGame = this.updateGame.bind(this);
    }

    updateGame() {

    }

    render() {
        return(
            <Board 
            board={this.state.board}
            updateGame={this.updateGame}/>
        )
    }
}

export default Game

Within Tile.jsx, I want the render to display adjacent bomb counts using the function from the main Tile js class (in minesweeper.js). This function is accessible when I first render my Tiles as React Components; however, if I change something (by going into components and updating), the function is no longer accessible. To help explain, here is the console.log of this.props.tile on the first render:

adjacentBombCount function accessible on first render

However, after re-rendering from updating a component, this is what this.props.tile looks like re-render, function missing.

Therefore, it will cause an error when I try to add the bomb count, as it cannot find the function. Can someone explain why the function is disappearing and how I can access it when Components change? Thanks!

1 Answer 1

1

This was an issue with the React DevTools specifically, and it will be addressed in an update, see: https://github.com/facebook/react/issues/24781

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.