简体   繁体   中英

React: Is it possible to prevent state update after unmount, via setting this.setState to empty function?

I am facing the problem that a network callback is trying to setState() of an unmounted component and receive the default console warning about this no-op.

It wasn't possible for me to track why the unmount happens but I found a solution suggesting to set the function to nothing in componentWillUnmount(). It didn't work and I tested to set this.setState to nothing. See below.

The error disappears but I want to ask whether that is a valid solution. Here the code:

  componentDidMount() {
    this.fetchLogItems(10, 'recentChanges');
  }

  componentWillUnmount() {
    this.setState = () => {};
  }

  fetchLogItems = (limit, stateRef) => {
    let tmpObj = {};
    base.fetch('_changelogs', {
      context: this,
      then(data) {
        tmpObj[stateRef] = {...data}
        tmpObj.loading = false;
        this.setState({...tmpObj})
      },
      catch(err){console.error(err)}
    });
  };

Two options:

  • be sure that whatever helpers that you are using also allow for the use of "destructors" (cancellations, and I definitely prefer the use of "cancellations")
  • if not, then you may introduce a "flag" to your class

If your library allows for some "cancellation", "destruction", or "cleanup", then you may simply do:

componentWillUnmount() {
  base.cancelFetch(); // or something similar.
}

Otherwise, you may be able to introduce a class property to your component. Perhaps name it isUnmounted . In componentWillUnmount , set this.isUmounted to true. Wrap the this.setState call in an if -statement that checks if isUnmounted is false, and if it is, then you may call this.setState . This is actually a very common pattern.

It may " feel " ugly, but, by defacto, this pattern seems to be idiomatic among React developers. If not, at least it is a pragmatic solution to problems similar to yours.

constructor() {
  // HERE
  this.isUmounted = false;
}

componentDidMount() {
  this.fetchLogItems(10, 'recentChanges');
}

componentWillUnmount() {
  // HERE
  this.isUmounted = true;
}

fetchLogItems = (limit, stateRef) => {
  let tmpObj = {};
  base.fetch('_changelogs', {
    context: this,
    then(data) {
      tmpObj[stateRef] = {...data}
      tmpObj.loading = false;
      // WRAP THE `this.setState` here.
      if (!this.isUnmounted) {
        this.setState({...tmpObj})
      }
    },
    catch(err){console.error(err)}
  });
};

However, I prefer the use of libraries and helpers that support cancellation. It's definitely guarantees some level of cleanup. Without cancellation, we risk introducing memory leaks.

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