yourknightmares
yourknightmares

Reputation: 323

setState updating a mounted state

While writing out Conway's Game of Life, I'm getting an error where the state's not actually being updated. I get a warning that setState(...): Can only update a mounted or mounting component. but everything I've tried so far to get rid of that hasn't helped. You can find my App Component below:

class App extends React.Component {
constructor(props) {
    super(props);
    this.state = {
        board: [],
        rows: 50,
        cols: 50,
        cycles: 0
    }
    this.createBoard();
}

createBoard() {
    var newBoard = [];
    for (var i = 0; i < this.state.rows; i++) {
        var row = [];
        for (var j = 0; j < this.state.cols; j++) {
            let fillValue;
            if (Math.random() > 0.65) {
                fillValue = true;
            } else {
                fillValue = false;
            }
            row.push(fillValue);
        }
        newBoard.push(row);
    }
    console.log(newBoard);
    this.setState({board: newBoard});
}

render() {
    return(
        <div id="root">
            <h1>Conway's Game of Life</h1>
            <Controller />
            {console.log(this.state.board)}
            <Board
                board={this.state.board}
                rows={this.state.rows}
                cols={this.state.cols}
            />
            <p>Years Passed: {this.state.cycles}</p>
        </div>
    );
}
}

The issue is with the setState at the end of the createBoard() function. The console.log above the setState prints out fine, but the other one in the render method prints out an empty array.

Upvotes: 0

Views: 60

Answers (2)

Dane
Dane

Reputation: 9582

It's exactly what the error says. You're setting state on an unmounted component. The component is not yet mounted when the constructor is called.
Do it inside componentDidMount() life cycle function:

class App extends React.Component {
constructor(props) {
    super(props);
    this.state = {
        board: [],
        rows: 50,
        cols: 50,
        cycles: 0
    };
    this.createBoard = this.createBoard.bind(this);
}

componentDidMount() {
    this.createBoard();
}

createBoard() {
    var newBoard = [];
    for (var i = 0; i < this.state.rows; i++) {
        var row = [];
        for (var j = 0; j < this.state.cols; j++) {
            let fillValue;
            if (Math.random() > 0.65) {
                fillValue = true;
            } else {
                fillValue = false;
            }
            row.push(fillValue);
        }
        newBoard.push(row);
    }
    console.log(newBoard);
    this.setState({board: newBoard});
}

render() {
    return(
        <div id="root">
            <h1>Conway's Game of Life</h1>
            <Controller />
            {console.log(this.state.board)}
            <Board
                board={this.state.board}
                rows={this.state.rows}
                cols={this.state.cols}
            />
            <p>Years Passed: {this.state.cycles}</p>
        </div>
    );
}
}

Please take a look at Lifecycle methods.

Upvotes: 1

Harsh Makadia
Harsh Makadia

Reputation: 3443

changing the place where you have called the createBoard() method fixes this error.Instead of calling method is constructor I moved it to componentDidMount Please note that your two components Board & Controller are missing in the code so I've commented them out

Here is the code

class TestJS extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            board: [],
            rows: 50,
            cols: 50,
            cycles: 0
        };
        this.createBoard = this.createBoard.bind(this);
    }

    componentDidMount(){
        this.createBoard();
    }

    createBoard() {
        var newBoard = [];
        for (var i = 0; i < this.state.rows; i++) {
            var row = [];
            for (var j = 0; j < this.state.cols; j++) {
                let fillValue;
                if (Math.random() > 0.65) {
                    fillValue = true;
                } else {
                    fillValue = false;
                }
                row.push(fillValue);
            }
            newBoard.push(row);
        }
        console.log(newBoard);
        this.setState({board: newBoard});
    }

    render() {
        return(
            <div id="root">
                <h1>Conway's Game of Life</h1>
                {console.log(this.state.board)}
                <p>Years Passed: {this.state.cycles}</p>
            </div>
        );
    }
}

export default TestJS;

Upvotes: 2

Related Questions