Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

this is the first time I face this warning message.

Can't call setState on a component that is not yet mounted.

Follows:

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 MyComponent component.

The "not yet mounted" part actually makes little to no sense as the only way to trigger the issue is to call a function by clicking a button from a component that needs to be mounted in order to see the button. The component is not unmounted at any given time neither.

This dummy component reproduces the error in my app:

import PropTypes from 'prop-types' import React from 'react'  export default class MyComponent extends React.Component {   constructor (props) {     super(props)     this.state = {       initial: 'state'     }     this.clickMe = this.clickMe.bind(this)   }    clickMe () {     this.setState({       some: 'new state'     })   }    render () {     return (       <div>         <button onClick={this.clickMe}>click</button>       </div>     )   } } 

I am using:

"react": "16.3.2", "react-dom": "16.3.2", "mobx": "4.2.0", "mobx-react": "5.1.2", 

Did I miss something in the latest React/mobx version? (note the component does not use any mobx related stuff but its parent is a mobx-react observer)

Edit:

There must be something related to the component instance, further investigation has shown that in some cases, creating an handler inside the render function will make this warning disappear, but not in all cases.

class MyComponent extends React.component {   constructor (props) {     // ...     this.clickMeBound = this.clickMe.bind(this)   }    clickMe () {     ...   }    render () {     // works     <button onClick={() => {this.clickMe()}}>click arrow in render</button>      // warning: Can't call setState on a component that is not yet mounted.     <button onClick={this.clickMeBound}>click bound</button>   } } 

Edit 2:

I have removed 'react-hot-loader/patch' from my entries in my Webpack config and some weird issues like this one have disappeared. I'm not putting this as an answer because the error message itself is still weird and this causes a warning in the console. Everything works fine though.

like image 485
Kev Avatar asked May 03 '18 19:05

Kev


People also ask

Can't call setState on a component that is not yet mounted React?

This error usually happens when you call the React setState method in a Class component's constructor. The reason is that the component state is not yet initialized when the constructor is called.

Can I call setState in componentDidMount?

You may call setState() immediately in componentDidMount() . It will trigger an extra rendering, but it will happen before the browser updates the screen.

What happens when you call setState () inside render ()?

What happens when you call setState() inside render() method? Nothing happens.

Why setState is not updating immediately?

setState , and React. useState create queues for React core to update the state object of a React component. So the process to update React state is asynchronous for performance reasons. That's why changes don't feel immediate.


1 Answers

This warning that you are getting is because you are setting a reference to clickMe method in the constructor, which is then using the setState().

constructor (props) {      super(props)      this.state = {         initial: 'state',         some: ''                }     this.clickMe = this.clickMe.bind(this);   <--- This method    }     clickMe () {     this.setState({       some: 'new state'    <-- the setState reference that is causing the issue     })    }

Try removing the this.clickMe = this.clickMe.bind(this) from constructor and do it in a lifecycle method like componentWillMount() or ComponentDidMount(). For react 16 and above you can use the componentWillMount method with "SAFE_" prefix. [SAFE_componentWillMount]

 componentWillMount() {        this.clickMe = this.clickMe.bind(this);   }    clickMe () {     this.setState({       some: 'new state'         })    }
like image 54
Anuj Shukla Avatar answered Sep 21 '22 04:09

Anuj Shukla