简体   繁体   中英

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

Gutentag, guys!

I keep getting this error message from my application after unmounting the component:

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.
    in Header (at index.js:27)

Now here is the code from the Header component:

class Header extends Component {
  isCancelled = false;
  state = {
    someStateVars: x,
    separateColumns: 'true',
  }

  handleChange = (event) => {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    if (!this.isCancelled) {
      this.setState({ //######THIS IS LINE 27######
        [name]: value
      });
    }
  }

  handleDisplayChange = (event) => {
    const value = event.target.value;
    const name = 'separateColumns';

    if (!this.isCancelled) {
      this.setState({  
        [name]: value
      }, () => {
        this.props.displayChange();
      });
    }
  }

  serversRefresh = () => {

    if (!this.isCancelled) {
      setTimeout(() => {
        this.setState({refreshed: false});
      }, localStorage.getItem('seconds')*1000); //disable refresh for 15 seconds
    }
  }

  reactivateButton = () => {
    if (!this.isCancelled) this.setState({refreshed: false});
  }

  componentDidMount() {
    if(localStorage.getItem('seconds')>5 && !this.isCancelled){
      this.setState({refreshed: true});
    }
  }

  componentWillUnmount() {
    this.isCancelled = true;
  }
}

When I saw I was getting this error, I've added isCancelled variable which is changed in componentWillUnmount() function to true.

After I unmount the Header component, after 15 seconds, when the serversRefreshbutton is reactivated, I get this error message.

How can I fix it?

On another component where I've encountered this issue "isCancelled" var did help, but here I see it has no impact and the issue persists.

Just store your timeout in a variable, eg

this.timeout = setTimeout(/* your actions here*/, /* your timeout */)

and then clear your timeout in the componentWillUnmount

componentWillUnmount() {
    clearTimeout(this.timeout)
}

It should fix your problem without crutches like this.isCancelled . Detecting component's mount state is no-op, because it still unloaded from memory even after unmounting.

setTimeout returns timer's id with which it can be cancelled in future. clearTimeout cancels timeout by it's id, if it is not yet executed.

More about your case you can read here: Why isMounted is antipattern .

More about timers on MDN .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM