I'm making a game where one makes a maze and then exports that maze to a database for others to try. I'm making a very large grid (800 x 800) and turning the squares black onMouseOver to indicate the walls of the maze. For a while, it seemed to be working well, but somewhere along the line, it started lagging onMouseOver, kind of killing the game. I'm not sure if I can make the divs change color fast enough to make this functional.

It seemed to be working fine until I moved the id of the Square component to the state of the Maze component in preparation to send it to the back end.

Here's the codesandbox: https://codesandbox.io/s/github/reedmacdonald/mazeProject


class Maze extends Component{
    constructor(props){
        super();
        this.state = {
            buttonClicked:'',
            buildShowing: 'inline',
            testShowing: 'none',
            testing: false,
            clicked: true,
            finishShowing:'inline',
            submitShowing:'none',
            maze:[],
            name:''

        }
    }


    changeToRed = () => {
        this.setState({
            submitShowing:'inline',
            finishShowing: 'none',
            buttonClicked:'red',
            testing: true})
    }



    nameThisMaze = (e) => {
        e.preventDefault()
        var nameValue = document.getElementById("uniqueID").value
        this.setState({
            name: nameValue
        })
        alert(`name is now ${this.state.name}`)
    }

    handleSubmit = async (e) => {
        e.preventDefault();
        const mazeResponse = await fetch('/maze', {
            method: 'POST',
            credentials: 'include',
            body: JSON.stringify(this.state),
            headers:{
                "Content-type" : 'application/json'
            }
        })
        const parsedResponse = await mazeResponse.json();
        console.log(parsedResponse)
    }

    pushValueUp = (brick) => {
        this.state.maze.push(brick)
        this.setState({
            maze:this.state.maze
        })
    }



    render(){
        const arrayOne= new Array(6400).fill('hello')

        const theMaze = arrayOne.map((movie, i) => {
            return (
                <Square pushValueUp = {this.pushValueUp} scar={i} clicked =
                {this.state.clicked} key={i} name="brick" button=
                {this.state.buttonClicked} color={this.state.colorToChangeMaze}
            className= 'cell'/>
        )
        })
        return (
            <div onDoubleClick={this.changeToClicked}>
            <div onMouseOver={(this.state.testing) ?
            this.outOfBounds:undefined} className="outOfBounds"></div>
            <div onMouseOver={(this.state.testing) ?
            this.outOfBounds:undefined} className="outOfBoundsTwo"></div>
            <div onMouseOver={(this.state.testing) ?
            this.outOfBounds:undefined} className="outOfBoundsThree"></div>
            <form onSubmit={this.handleSubmit}>
            <button type="button" onClick={this.changeButtons}
        className="finishMaze" style=
            {{'display':this.state.finishShowing}}>Finish Maze</button>
        <button type="submit" className="finishMaze"
        style=``{{'display':this.state.submitShowing}}>Submit Maze</button>

        <div className="grid">
            {theMaze}
            </div>
            </form>

            <button className="startEndButton" onClick={this.changeToRed} style={{'display':this.state.testShowing}}>Test Maze</button>
        <button className="startEndButton" onClick={this.changeToBlack} style={{'display':this.state.buildShowing}}>Build Maze</button>

        <form className="nameForm" onSubmit={this.nameThisMaze}>
            <input id = "uniqueID" name = "mazeName" className="giveName" type="text" placeholder=" Name of Your maze"></input>
            <button type="submit"> Give name</button>
        </form>
        </div>
    )}
}

class Square extends Component{
    constructor(props) {
        super(props);
        this.state = {
            scar: this.props.scar,
            color: 'white',
            colorToChange:null,
            changeColor: false,
            clicked:this.props.clicked
        };
    }


    darnThis = () =>{
        this.props.pushValueUp(this.props.scar)
    }
    switchColor =()=>{
        (this.state.colorToChange==='black' && this.props.button=== 'red')&& this.hitWall()
        this.darnThis()
        this.setState({
            changeColor:true,
            colorToChange:this.props.button})
    }
    render(){
        return(
            <div className="boxes" onMouseOver = {this.switchColor} style={{'height':'5px','width':'5px','backgroundColor':this.state.changeColor ? this.state.colorToChange : this.state.color,'margin':'0'}}>
    </div>
    )
    }
}

I'm sorry I put so much code in there (I took out a good amount, in case you get confused as to where things went), I just don't know why the onMouseOver is lagging so much.

1 Answers

2
Maaz Syed Adeeb On Best Solutions

A few problems which I saw and fixed.

  1. The 6400 sized array is not required to be created every time, since you only need to iterate 6400 times. Just create it once outside the components and use it via scope lookup.
  2. maze is not used anywhere to render. So you can just keep it on the Maze instance, as this.maze. Calling setState will unnecessarily re-trigger the whole React lifecycle.
  3. You call switchColor always in the onMouseOver handler. That's pretty expensive when coupled with a setState in the parent. Especially since the event is fired very often. So, I've moved the call to parent into componentDidUpdate and written some condition (prevState.colorToChange !== this.state.colorToChange) based on which parent is called. You should change this condition to suit your needs.

Codesandbox is here. These are just some optimisations that I could think of, and the app seems to be responding well. Also remember, you should not modify state directly.

I experimented by using refs on each square. I didn't have time to make a full-fledged example, but the idea is there. link.