Home > Back-end >  Cannot perform a React state update on an unmounted component. Indicates memory leak
Cannot perform a React state update on an unmounted component. Indicates memory leak

Time:10-05

I am a new learner in react. I am displaying the react apex charts by retrieving data using axios. I tried many ways to unmount it but couldn't figure the correct way of doing it. Its generating an error saying. Warning: 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.

How to unmount and cancel all subscriptions?

I have attached my code and the UI here below.
import React, {Component} from "react";
import GridWrapper from "../helpers/gridWrapper";
import Chart from 'react-apexcharts'
import ContentWrapper from "../helpers/contentWrapper";
import GridWrapperL from "../helpers/twoSideBySideWrapper/gridWrapperL";
import axios from "axios";


let source = axios.CancelToken.source();
export default class Charts extends Component{
 


  constructor(props) {
    super(props);
    this._isMount= false;
    this.state = {
      options: {
        chart: {
          id: 'apexchart-example'
        },
        xaxis: {
          categories: [1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999]
        }
      },
      series: [{
        name: '',
        data: [],
      },
      { name:"In progress stages",
      data:[],
  },

  { name:"Completed stages",
  data:[],
},
      // {
      //   name: 'Team B',
      //   data: [10, 70, 35, 55, 49, 80, 70, 55, 12]
      // },
    
    ]
    }
    source = axios.CancelToken.source();
  }

  
  async componentDidMount(){
    this._isMount=true;
    const salary=[]; const age=[]; const stages=[];

    //Getting projects details
      await axios.get('http://localhost:5000/api/projects',  {
        cancelToken: source.token
      }).then (Response=>{
        const data=[] = Response.data.projects; 
        var todo=0; var inprogress=0; var done=0;
        const emp_name=[]; const projectID=[]; const project_name=[]; 
        const todoARR=[] ; const inProgressArr=[]; const readyArr=[];
        

        //Checking conditions for each projects
        data.forEach(element => {
         // console.log(element._id);
          project_name.push(element.projectName);
          projectID.push(element._id);
        //  projectID.forEach(element =>{
            console.log("stage")
            
            axios.get(`http://localhost:5000/api/auth/stages/findproject/projectId?id=${element._id}` ,   {
              cancelToken: source.token
            }).then (Response2=>{
              const data2=Response2.data.stage;

              //Collecting information about the stages for each project
              data2.forEach(element2 => { 
            //  console.log(Response2, "HEY....................................")
              //console.log(element2.status   "HERE")
              if(element2.status == "TO-DO"){
                todo = todo 1;
              }
              if(element2.status == "IN-PROGRESS"){
             //   console.log("Yes")
                inprogress = inprogress 1;
              }
  
              if(element2.status == "READY"){
                done=done 1;
              }})
            
             // console.log(todo,inprogress,done);
              todoARR.push(todo);
              inProgressArr.push(inprogress);
              readyArr.push(done);
              todo=0; inprogress=0; done=0;
  
        
         });
  
      // console.log(stages)
       //console.log(project_name   "projects");
  
        })
//Setting Apex chart data
      console.log("salary", age);
      if(this._isMount){
      
      this.setState({
        options: {
          chart: {
            id: 'apexchart-example'
          },
          xaxis:{
            categories:project_name,
          }
        },
        series: [{
          name: 'Todo stages',
          data: todoARR,
        },
         { name:"In progress stages",
          data:inProgressArr,
      },

      { name:"Completed stages",
      data:readyArr,
  },
      ]
      
      })
    }
    })
    
    .catch(err =>{
      console.log("error", err)
    })

  }


  async componentWillUnmount() {
    this._isMounted = false;
    // this.setState({
    //   options: {
    //     chart: {
    //       id: 'apexchart-example'
    //     },
    //     xaxis:{
    //       categories:[1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999],
    //     }
    //   },
    //   series: [{
    //     name: '',
    //     data: [],
    //   }],
      

    
    
   // })
 }

 setState = (state, callback) => {
  if (this._isMount) {
    super.setState(state, callback);
  }
}
 
  render(){
  return(
 
        <center>
    <div>
     
      {/* We can change the type by simply typing "line" */}
      <Chart options={this.state.options} series={this.state.series} type="bar" width={1000} height={520} />
    </div>
    </center>
 
  );
  }
};

enter image description here

CodePudding user response:

The problem here is that you're firing a setState on an unmounted component.

I can't really figure out what is the issue here by looking at your code.

Setting componentDidMount and componentWillUnmount to be async will only make the problem harder to spot, IMHO.

I could guess that some other condition in the tree above is unmounting this component before the fetch in componentDidMount finishes, and you're setting state on an unmounted component.

CodePudding user response:

You're not cancelling your axios token once your component unmounts; On your componentWillUnmount, add the following:

source.cancel("Component unmounted, request is cancelled.");

Docs: https://axios-http.com/docs/cancellation

  • Related