componentDidMount: Can't call setState (or forceUpdate) on an unmounted component

componentdidmount react
componentdidmount functional component
componentdidmount hooks
componentdidmount setstate
componentwillmount deprecated
react lifecycle diagram
componentdidupdate setstate
react setstate callback

I am fetching data in componentDidMount and updating the state and the famous warning is appearing:

Warning: Can't call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.

My code is as follow:

componentDidMount() {
    let self = this;

    let apiBaseUrl = Config.serverUrl;
    axios.get( apiBaseUrl + '/dataToBeFetched/' )
        .then( function(response) {
            self.setState( { data: response.data } );;
        } );
}

What is causing this warning and what is the best way to fetch the data and update the state?

Based on a previous answer, I have done the following which worked fine:

constructor(props) {
   this.state = {isMounted: false}
}

componentDidMount() {
    let apiBaseUrl = Config.serverUrl;
    this.setState( { isMounted: true }, () => {
        axios.get( apiBaseUrl + '/dataToBeFetched/' )
            .then( (response) => { // using arrow function ES6
                if( this.state.isMounted ) {
                    this.setState( { pets: response.data } );
                }
            } ).catch( error => {
                // handle error
        } )
    } );
}

componentWillUnmount() {
    this.setState( { isMounted: false } )
}

Another better solution is to cancel the request in the unmount as follows:

constructor(props) {
    this._source = axios.CancelToken.source();
}

componentDidMount() {
    let apiBaseUrl = Config.serverUrl;
    axios.get( apiBaseUrl + '/dataToBeFetched/', { cancelToken: this._source.token } )
        .then( (response) => { // using arrow function ES6
            if( this.state.isMounted ) {
                this.setState( { pets: response.data } );
            }
        } ).catch( error => {
            // handle error
    } );
}

componentWillUnmount() {
    this._source.cancel( 'Operation canceled due component being unmounted.' )
}

State and Lifecycle – React, You can find a detailed component API reference here. When the Clock output is inserted in the DOM, React calls the componentDidMount() lifecycle method. What is componentDidMount () componentDidMount () is a hook that gets invoked right after a React component has been mounted aka after the first render () lifecycle. class App extends React.Component { componentDidMount() { // Runs after the first render () lifecycle } render() { console.log('Render lifecycle') return < h1 > Hello </ h1 >; } }

You can try this:

constructor() {
    super();
    this._isMounted = false;
}

componentDidMount() {
    this._isMounted = true;
    let apiBaseUrl = Config.serverUrl;
    this.setState( { isMounted: true }, () => {
        axios.get( apiBaseUrl + '/dataToBeFetched/' )
            .then( (response) => { // using arrow function ES6
                if( this._isMounted ) {
                    this.setState( { pets: response.data } );
                }
            } ).catch( error => {
                // handle error
        } )
    } );
}

componentWillUnmount() {
    this._isMounted = false; // equals, not :
}

React Lifecycle Methods Render And ComponentDidMount, In that scenario, you can do something like this. import { Component } from 'react'; class App extends Component  componentDidMount() method is the perfect place, where we can call the setState() method to change the state of our application and render() the updated data loaded JSX. For example, we are going to fetch any data from an API then API call should be placed in this lifecycle method, and then we get the response, we can call the setState() method and render the element with updated data.

This most likely happened because the component was already unmounted before the async call finished. Meaning, your call to setState in the axios promise is being called after the component is already unmounted, perhaps because of a react-router Redirect or a change in state?

Understanding React componentDidMount and how it works, integration with other JavaScript frameworks and any functions with delayed execution such as setTimeout or setInterval. componentDidMount() is part of the React component lifecycle methods, methods that get called automatically by the React system at specific points in the life of a component. Another such methods is componentDidUpdate(). componentDidUpdate()is called after componentDidMount() and can be useful to perform some action when the state changes.

Call setState on componentWillUnmount is the worst practice

componentWillUnmount() {
    this.setState( { isMounted: false } ) // don't do this
}

ReactJS - Component Life Cycle, , make sure your component has a unique key. With the key set, React will interpret them as different components and handle unmounting and mounting. The componentDidMount() method can be a helpful heavy lifter for our Components. One of the most common tasks is interacting with the Native UI. Unlike componentWillMount() or render() we can now fully interact with the Native stack. For example, we may need to make changes to our current state based on how the Native UI laid out our content.

How to call ComponentDidMount() of different component from , This guarantees the parent can access the Native UI elements for itself and its children. +. Let's consider the following three components and their call order. +. The async keyword is absolutely harmless. I cannot imagine any situation in which you need to make a call to the componentDidMount () method so the return type Promise<void> is harmless too. Calling to a method having return type of Promise<void> without await keyword will make no difference from calling one having return type of void.

componentDidMount() not being called when react component is , Does componentDidMount() only run once? Is componentDidMount() a good lifecycle to fetch data? Can I use async/await on componentDidMount() ? What is​  You cannot use any of the existing lifecycle methods ( componentDidMount, componentDidUpdate, componentWillUnmount etc.) in a hook. They can only be used in class components. And with Hooks you can only use in functional components. The line below comes from the React doc:

Post-Mount with componentDidMount() · react-indepth, You can use the constructor method or componentDidMount depending on what you need to be done. constructor will be called pre-render and  The subscription logic is also spread between componentDidMount and componentWillUnmount. And componentDidMount contains code for both tasks. So, how can Hooks solve this problem? Just like you can use the State Hook more than once, you can also use several effects. This lets us separate unrelated logic into different effects:

Comments
  • You didn't explain the cause of the error. Is it that the component is mounting and then subsequently un-mounting before the async get call and setState calls finish?
  • Yes, that's right. The unmounting doesn't wait for the async call to finish. Eventually when the async call gets over, the component is already unmounted and so it cannot set the state and you wouldn't want to do that anyways. To do this, the method in the answer above simply does a check to see if the component is mounted before setting the state.
  • @O_k Thanks! why the need to do the AJAX inside the this.setState - i.e. this.setState( { isMounted: true }, () => { ... ?
  • @dowi this is to make sure that isMounted is set before you do the axios call. Using setState does not change the state immediately.
  • Can you explain which part of "this" makes the difference? You should do so such that others can learn from your answer
  • no need to set state, this code also works without setting state of isMounted.