0

I've found some thread about this problem, but none of them solved mine.

Can't call setState on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application.

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

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

import React, { Component } from 'react';
import { Card, CardHeader, CardBody, Button, Collapse } from 'reactstrap';

class MyComponent extends React.Component<any, any> {
  constructor(props) {
    super(props);
    this.toggle = this.toggle.bind(this);
    this.state = {
      collapse: false,
    };
  }

  toggle() {
    this.setState({ collapse: !this.state.collapse });
  }

  render() {
    return (
          <Card>
            <CardHeader>
              <Button color="link" onClick={this.toggle} className="float-right">
                Click me to toggle collapse
              </Button>
            </CardHeader>
            <Collapse isOpen={this.state.collapse}>
              <CardBody>
                The content being collapsed
              </CardBody>
            </Collapse>
          </Card>
    );
  }
}

export default MyComponent;
  • If i put in componentDidMount() { console.log("Mounted!"); } then sure, it still appear in the console window.
  • I've tried answers from similar threads such as install babel polyfill, delete react-hot-loader, but none of them works.
  • I get this problem in every components I have setState and a button (or something similar) to call the method.
  • Anyone have the idea to fix? I appreciate every of them. Many thanks
Tung Le
  • 31
  • 1
  • 8
  • 1
    Please update your question with a [mcve] demonstrating the problem, ideally a **runnable** one using Stack Snippets (the `[<>]` toolbar button). Stack Snippets support React, including JSX; [here's how to do one](http://meta.stackoverflow.com/questions/338537/). You've used Stack Snippets, but not made it runnable (clicking "Run code snippet" fails because it's missing the libraries, uses export, has TypeScript type annotations, etc.). – T.J. Crowder Mar 18 '19 at 09:49
  • It's not the problem, but ths is wrong: `this.setState({ collapse: !this.state.collapse });` When you're setting state based on existing state, you **must** use the callback version: `this.setState(({collapse}) => ({collapse: !collapse }));` More: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous (But again, that's not the problem, the symptom would be different.) – T.J. Crowder Mar 18 '19 at 09:50
  • You should bind the onClick event like this: onClick={this.toggle.bind(this)} and remove the this.toggle on the constructor – jgoday Mar 18 '19 at 09:51
  • @jgoday - No, doing it in the constructor isn't just okay, it's more efficient and a standard idiom. – T.J. Crowder Mar 18 '19 at 09:52
  • @T.J.Crowder sorry, you are completely right. Error must be in another thing. Minimal sample (https://jsfiddle.net/7a6drL35/1/) works just right. – jgoday Mar 18 '19 at 09:58
  • jsfiddle from jgoday works well. I've read another threads about this problem before. They said something went wrong in dependencies. Should i add my package.json? – Tung Le Mar 18 '19 at 10:08
  • and by the way, callback version of setState doesn't solve the problem – Tung Le Mar 18 '19 at 10:10
  • You can add package,json but what you need to do is to provide a way to replicate the problem. Without it it's a guesswork. MyComponent that was posted can't cause this problem, no matter what dependencies are. – Estus Flask Mar 18 '19 at 10:47

2 Answers2

0

You receive this error because you try to change the state of a component that is not mounted. This can happen if a callback is triggered after the component has been unmounted from within its parent.

You can track the mount status of the component as follows :

import React, { Component } from 'react';
import { Card, CardHeader, CardBody, Button, Collapse } from 'reactstrap';

class MyComponent extends React.Component<any, any> {
  mounted = false;

  constructor(props) {
    super(props);
    this.toggle = this.toggle.bind(this);
    this.state = {
      collapse: false,
    };
  }

  componentWillMount() { this.mounted = true; }
  componentWillUnmount() { this.mounted = false; }

  toggle() {
    if(this.mounted) {
       this.setState(({collapse}) => ({ collapse: !collapse }));
    }
  }

  render() {
    return (
          <Card>
            <CardHeader>
              <Button color="link" onClick={this.toggle} className="float-right">
                Click me to toggle collapse
              </Button>
            </CardHeader>
            <Collapse isOpen={this.state.collapse}>
              <CardBody>
                The content being collapsed
              </CardBody>
            </Collapse>
          </Card>
    );
  }
}

export default MyComponent;
Scalpweb
  • 1,971
  • 1
  • 12
  • 14
0

Somehow, problem is solved when I build the production

.\mvnw -Pprod -DskipTests

. Many thanks for those who spent time helping me.

Tung Le
  • 31
  • 1
  • 8
  • 4
    This is a bad thing to do: do not skip tests to build for production. You should try to fix your issue instead. – Scalpweb Mar 18 '19 at 12:50