Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React memory leak, componentDidUnmount not working

I have reviewed many posts attempting to resolve this issue and have tried numerous ways to take care of this error, but the answer stills eludes me. It is a common problem, I know, but my understanding of React appears to be inadequate to achieve resolution. I'm trying to eliminate this error:

Can't perform a React state update 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.

I am unable to understand why componentWillUnmount does not resolve it. Here is the code:

import React from 'react';
import ReactDOM from 'react-dom';

export class PracticeData extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      data: [],
      isLoaded: false,
    }
}
componentDidMount() {
  this.mounted=true;
  fetch('https://jsonplaceholder.typicode.com/users')
  .then(res => res.json())
  .then(json => {
    this.setState({   //triggers a rendering cycle
      isLoaded: true,
      data: json,
    })
  });
} 
componentWillUnmount(){
  this.isLoaded=false;
}
  render(){
    var { isLoaded, data } = this.state;
      if(!isLoaded) {
        return <div>Loading...</div>
      } else {
       return (
         <div className="container-fluid">
           <div className="row">{
             data.map(data => <div key={data.id}>
               <div className="list">
                 <li className="header">{data.name}</li>
               <div className="body">  
                 <li><strong>Company:</strong> {data.company.name}</li>
                 <li><strong>User Name: </strong> {data.username}</li>
                 <li><strong>Email: </strong> {data.email}</li>
                 <li><strong>Phone: </strong>{data.phone}</li>
               </div>
                 <li className="address"><strong>Address: </strong></li>
               <div className="body">
                 <li><strong>Street:</strong> {data.address.street}</li>
                 <li><strong>Suite: </strong> {data.address.suite}</li>
                 <li><strong>City: </strong> {data.address.city}<br/></li>
                 <li><strong>Zip Code:</strong> {data.address.zipcode}</li>
               </div>   
               </div>
               </div>
              )}
           </div>
          </div>
        );
      }
    }
  }
ReactDOM.render(<PracticeData/>, document.getElementById('root'));
like image 440
Ron Avatar asked Dec 06 '25 15:12

Ron


1 Answers

The fetch looks like the only thing that can possibly resolve after a component unmounts, and for this you'll need an AbortController.

Basic usage is

const controller = new AbortController();
const { signal } = controller;

fetch(url, { signal })

Later if needed, you can abort the fetch

controller.abort()

Update to your component

export class PracticeData extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      data: [],
      isLoaded: false,
    }
  }

  controller = new AbortController();

  componentDidMount() {
    this.mounted=true;
    const { signal } = this.controller;

    fetch('https://jsonplaceholder.typicode.com/users', { signal }) // <-- pass signal in fetch options
      .then(res => res.json())
      .then(json => {
        this.setState({
          isLoaded: true,
          data: json,
        })
      })
      // catch any rejected fetch promises (including aborted fetches!)
      .catch(console.error);
  }

  componentWillUnmount(){
    this.isLoaded=false;
    this.controller.abort(); // <-- abort any in-flight fetch requests
  }
...

Edit cancel fetch request on unmount

NOTE: fetch normally only returns rejected Promises for network errors, valis HTML error responses will return in resolved Promises. As noted in comment, aborted fetches will also return a rejection.

like image 110
Drew Reese Avatar answered Dec 09 '25 18:12

Drew Reese



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!