Getting a warning called Can't call setState on a component that is not yet mounted

Viewed 2030

This is my code

import React, { Component } from 'react';

class Rando extends Component {
    constructor(props) {
        super(props); // want to use props insode brackets if we want to use props inside the constructor
        this.state = { num: 0, color: 'purple' };
        this.makeTimer();
    }

    makeTimer() {
        setInterval(() => {
            let rand = Math.floor(Math.random() * this.props.maxNum);

            this.setState({ num: rand });
        }, 10);
    }
    render() {
        console.log('changing');
        return (
            <div className=''>
                <h1>{this.state.num}</h1>
            </div>
        );
    }
}

export default Rando;

I'm getting a warning that looks like this

index.js:1 Warning: Can't call setState on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to this.state directly or define a state = {}; class property with the desired state in the Rando component.

I'm a beginner, I have no idea what's causing this. please help me. Thanks in advance

4 Answers

Your timer function gets executed even before the component gets mounted. Try putting the code inside componentDidMount hook. Also don't forget to clear the interval id inside componentWillUnmount.

Sandbox link for your reference: https://codesandbox.io/s/react-basic-class-component-forked-sybv0?file=/src/index.js

Modified Snippet

import React, { Component } from 'react';

class Rando extends Component {
    constructor(props) {
        super(props); 
        this.state = { num: 0, color: 'purple' };
        this.timer = null;
    }

     componentDidMount() {
        this.makeTimer();
     }
   
     componentWillUnmount() {
        clearInterval(this.timer);
     }

    makeTimer = () => {
        this.timer = setInterval(() => {
            let rand = Math.floor(Math.random() * this.props.maxNum);
            this.setState({ num: rand });
        }, 10);
    }

    render() {
        return (
            <div>
                <h1>{this.state.num}</h1>
            </div>
        );
    }
}

export default Rando;

You should call this.makeTimer(); on componentDidMount() instead of constructor

componentDidMount(){
  this.makeTimer();
}

Try this code

import React, { Component } from 'react';

class Rando extends Component {
    constructor(props) {
        super(props); // want to use props insode brackets if we want to use props inside the constructor
        this.state = { num: 0, color: 'purple' };
        this.makeTimer((data) => {
          this.setState(data);
        });
    }

    makeTimer(cb) {
        setInterval(() => {
            let rand = Math.floor(Math.random() * this.props.maxNum);

            
            cb({ num: rand })
        }, 10);
    }
    render() {
        console.log('changing');
        return (
            <div className=''>
                <h1>{this.state.num}</h1>
            </div>
        );
    }
}

export default Rando;

Try this :

import React, { Component } from 'react';

class Rando extends Component {
    constructor(props) {
        super(props); // want to use props insode brackets if we want to use props inside the constructor
        this.state = { num: 0, color: 'purple' };
    }

    makeTimer() {
        setInterval(() => {
            let rand = Math.floor(Math.random() * this.props.maxNum);

            this.setState({ num: rand });
        }, 10);
    }

    componentDidMount(){
    this.makeTimer();
    }

    render() {
        console.log('changing');
        return (
            <div className=''>
                <h1>{this.state.num}</h1>
            </div>
        );
    }
}

export default Rando;
Related