0

I am performing an API call that kicks off with componentDidMount, however when a new component is loaded by the user, there is a notification for a potential memory leak, see below for message. I have researched different solutions but have found nothing yet that works, I'm wondering if this can be fixed within this particular component with a componentWillUnmount or if it is better handled within the axios call itself.

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.

componentDidMount() {
    this.loadBackground();
    this.getUpdatedWeather();
    this.getNewMartianPhotos();
  }

  checkMartianPhotos = () => {
    if (this.state.martianMotion) {
      console.log('still shooting');
      this.getNewMartianPhotos();
    } else {
      return console.log('done now');
    }
  };

  getNewMartianPhotos = () => {
    let loadedImage = '';
    let loadedInfo = '';
    let loadedMeta = '';
    let totalImage;

    API.getMarsPhotos().then(data => {
      // console.log(data.data);
      // console.log(
      //   data.data.collection.items[this.state.martianCount].data[0].photographer
      // );
      // console.log(
      //   data.data.collection.items[this.state.martianCount].data[0].description
      // );
      // console.log(
      //   data.data.collection.items[this.state.martianCount].links[0].href
      // );

      totalImage = data.data.collection.items.length;
      loadedImage =
        data.data.collection.items[this.state.martianCount].links[0].href;
      loadedInfo =
        data.data.collection.items[this.state.martianCount].data[0].description;
      loadedMeta =
        data.data.collection.items[this.state.martianCount].data[0]
          .photographer;

      this.setState({
        martianImage: loadedImage,
        martianDescription: loadedInfo,
        martianMeta: loadedMeta,
        martianCount: this.state.martianCount + 1
      });

      if (this.state.martianCount < totalImage) {
        console.log(
          `shooting off, image count now ${this.state.martianCount} against ${totalImage}`
        );
        setTimeout(this.checkMartianPhotos, 10000);
      }
    });
  };

  componentWillUnmount() {
    clearTimeout(this.checkMartianPhotos);
  }


-------------------------------------

const CancelToken = axios.CancelToken;
const source = CancelToken.source();

  getMarsPhotos: () =>
    axios
      .get('https://images-api.nasa.gov/search?q=martian', {
        cancelToken: source.token
      })
      .catch(function(thrown) {
        if (axios.isCancel(thrown)) {
          console.log('request canceled', thrown.message);
        } else {
          console.log('there is an error that needs to be handled');
        }
      })
JakeG9191
  • 3
  • 6
  • Try cancelling the request in `componentWillUnmount`. – cbr Mar 01 '20 at 19:04
  • Maybe canceling the request is not enough and you need canceling the promise see https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html. if you use redux, you can use redux-saga for cancellation. But first understand why this happens, maybe it's bad implementation. share codesandbox for better examination. – gadi tzkhori Mar 01 '20 at 19:56

1 Answers1

0

As the error informs, your component is calling setState after it has been unMounted. This is because you are clearing your timeout incorrectly. You should be doing the following to properly clear your timeout on unmount.

this.id = setTimeout(this.checkMartianPhotos, 10000);

And then clear with

clearTimeout(this.id)

In componentWillUnmount

Also, try to move your async logic (api calls) out of your component.

Refer to this to see how to stop setting a state after an API call on unmounted component.

Hassaan Tauqir
  • 2,464
  • 1
  • 13
  • 11
  • Well the react docs state that isMounted is anti pattern see https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html – gadi tzkhori Mar 01 '20 at 20:18
  • @gadi tzkhori True! That is why I requested the OP to move async logic out of the component. Thanks for the share btw. – Hassaan Tauqir Mar 01 '20 at 20:27
  • Hi Hassaan, I wanted to let you know that this did solve my issue, and I greatly appreciate the help. My API call is in a separate file but I wanted to include the info in case it gave any insight, I'll read up further on the topic with the link you left, thanks again – JakeG9191 Mar 01 '20 at 20:32