Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate

I'm making this Conway's game of life react project and it was working just fine but when I added the last couple of buttons to clear the board and some other functionalities react gave me this error

Maximum update depth exceeded. This can happen when a component 
repeatedly calls setState inside componentWillUpdate or 
componentDidUpdate. React limits the number of nested updates to 
prevent infinite loops. 

From the code snippets it's been showing me it seems that the clear() function is the problem here, but I don't think I did set state inside a render() to trigger an infinite loop. Here are all the code for the clear and componentDidMount, I don't have a componentWillUpdate or componentDidUpdate in my app.

the clear() and Play function in the main class

EDIT 1 : It's telling me that there's something wrong with the setState inside the play() function, however, I always implemented the play function this way and it was always working since the beginning....

clear = ()=>{
    var g = Array(this.rows).fill().map(()=> Array(this.cols).fill(false));

    this.setState({
        generations:0,
        fullGrid: g
    })
}

.....

play = () => {

    let g1 = this.state.fullGrid;
    let g2 = arrayClone(this.state.fullGrid);

    for (let i = 0; i < this.rows; i++) {
        for (let j = 0; j < this.cols; j++) {
            let count = 0;

            if (i > 0)
                if (g1[i - 1][j]) count++;
            if (i > 0 && j > 0)
                if (g1[i - 1][j - 1]) count++;
            if (i > 0 && j < this.cols - 1)
                if (g1[i - 1][j + 1]) count++;
            if (j < this.cols - 1)
                if (g1[i][j + 1]) count++;
            if (j > 0)
                if (g1[i][j - 1]) count++;
            if (i < this.rows - 1)
                if (g1[i + 1][j]) count++;
            if (i < this.rows - 1 && j > 0)
                if (g1[i + 1][j - 1]) count++;
            if (i < this.rows - 1 && this.cols - 1)
                if (g1[i + 1][j + 1]) count++;
            if (g1[i][j] && (count < 2 || count > 3)) g2[i][j] = false;
            if (!g1[i][j] && count === 3) g2[i][j] = true;
        }
    }

    this.setState({
        fullGrid: g2,
        generations: this.state.generations + 1
    });

}


playButton = ()=>{
    clearInterval(this.intervalId);
    this.intervalId = setInterval(this.play, this.speed);
}

pauseButton = ()=>{
    clearInterval(this.intervalId);
}

slow = ()=>{
    this.speed = 1000;
    this.playButton();
}

fast = ()=>{
    this.speed = 100;
    this.playButton();
}

clear = ()=>{
    var g = Array(this.rows).fill().map(()=> Array(this.cols).fill(false))

    this.setState({
        generations:0,
        fullGrid: g
    })
}

The Button Class

class Buttons extends React.Component{

handleSelect = (evt) =>{
    this.props.gridSize(evt);
}

render(){
    return (
        <div className="center">
            <ButtonToolbar>
                <button className='btn btn-info'  onClick={this.props.playButton}>
                    PLAY
                </button>
                <button className='btn btn-info'  onClick={this.props.pauseButton}>
                    PAUSE
                </button>
                <button className='btn btn-info'  onClick={this.props.clear}>
                    CLEAR
                </button>
                <button className='btn btn-info'  onClick={this.props.slow}>
                    SLOW
                </button>
                <button className='btn btn-info'  onClick={this.props.fast}>
                    FAST
                </button>
                <button className='btn btn-info'  onClick={this.props.seed}>
                    SEED
                </button>
                <DropdownButton
                    title="Grid Size"
                    id="size-menu"
                    onSelect={this.handleSelect}
                >
                    <MenuItem eventKey="1">20x10</MenuItem>
                    <MenuItem eventKey="2">50x30</MenuItem>
                    <MenuItem eventKey="3">70x50</MenuItem>
                </DropdownButton>
            </ButtonToolbar>
        </div>
    )
}

}

like image 261
UWGOOSE Avatar asked Mar 11 '18 16:03

UWGOOSE


People also ask

Can we use setState in componentDidUpdate?

You may call setState() immediately in componentDidUpdate() but note that it must be wrapped in a condition like in the example above, or you'll cause an infinite loop. It would also cause an extra re-rendering which, while not visible to the user, can affect the component performance.

How many times does componentDidMount get called?

2. How many times componentDidMount is called? React components call componentDidMount only once by default. You can run the component multiple times if you delete the component or change the props or state.

What is componentDidUpdate prevProps?

The componentDidUpdate()is called after componentDidMount() and can be useful to perform some action when the state of the component changes. Syntax: componentDidUpdate(prevProps, prevState, snapshot) Parameters: Following are the parameter used in this function: prevProps: Previous props passed to the component.

Can we use setState in shouldComponentUpdate?

shouldComponentUpdate() Safe to use setState ? Yes! This method is called whenever there is an update in the props or state. This method has arguments called nextProps and nextState can be compared with current props and currentState .


1 Answers

Your onClick handlers are being called continuously. Change them to functions that return the function you wish to call and this should fix your issue.

Example:

<button className='btn btn-info'  onClick={() => this.props.playButton}>
    PLAY
</button>
like image 173
Sean Avatar answered Oct 05 '22 22:10

Sean