Search code examples
javascriptreactjsreact-lifecycle

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


I'm trying to fetch the data from the server after component has been updated but I couldn't manage to do that. As far as I understand componentWillUnmount is called when component is about to be destroyed, but I never need to destroy it so it's useless to me. What would be solution for this? When I should set the state?

async componentDidUpdate(prevProps, prevState) {
  if (this.props.subject.length && prevProps.subject !== this.props.subject) {
    let result = await this.getGrades({
      student: this.props.id,
      subject: this.props.subject
    });
    this.setState({
      subject: this.props.subject,
      grades: result
    });
  }
}

async getGrades(params) {
  let response, body;

  if (params['subject'].length) {
    response = await fetch(apiRequestString.gradesBySubject(params));
    body = await response.json();
  } else {
    response = await fetch(apiRequestString.grades(params));
    body = await response.json();
  }

  if (response.status !== 200) throw Error(body.message);

  return body;
}

Full error:

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.

Solution

  • A common pattern I use in this instance is something along the lines of

    componentWillUnmount() {
        this.isCancelled = true;
    }
    

    And then in the code where you're awaiting an async function to resolve, you would add a check before setting state:

    async componentDidUpdate(prevProps, prevState) {
        if (this.props.subject.length && prevProps.subject !== this.props.subject) {
            let result = await this.getGrades({
                student: this.props.id,
                subject: this.props.subject
            });
            !this.isCancelled && this.setState({
                subject: this.props.subject,
                grades: result
            });
        }
    }
    

    That will stop any state setting on unmounted/unmounting components