Anoop K George
Anoop K George

Reputation: 1735

Unable to stop memory leak in useEffect hook ,React JS

I have a landing page in React with below function for changing image in carousel.

After I navigate away, it gives error 'Can't perform a React state update on an unmounted component.'

Below function change carousel image in every 2 second.

  // state to find idex
  const [imageIndex, setImageIndex] = React.useState(0); 

  //array of images to display
  const images =  [
  image1,image3,image2,
    ];
    
  //function that changes image index in every 2 second
  const nextImage = () => {
    setImageIndex((prev) => (prev + 1) % images.length);
    setTimeout(nextImage, 2000);
  };

  // function to initiate above function, the memory leak happens here
  React.useEffect(nextImage, []);

I have gone through some StackOverflow questions and changed my timing function as below but the error still exists,

// useEffect triggers this functions

const nextImage = () => {
    let unmounted = false;
    if (!unmounted) {
      setImageIndex((prev) => (prev + 1) % images.length);
      setTimeout(nextImage, 2000);
    }

    return () => {
      unmounted = true;
    };
  };

Question I referred https://stackoverflow.com/a/58038029/10515390 have answer but I did not get the clear idea.

Upvotes: 0

Views: 239

Answers (1)

Sifat Haque
Sifat Haque

Reputation: 6067

Here i've created a simple snippet for you. Hope you'll understand this. And since you are using setTimeout make sure you've also used clearTimeout. And re run the effect when the image index changes.

const {useState, useEffect} = React;

function Test() {
    const [imageIndex, setImageIndex] = React.useState(0); 

    const images =  [ 'image1','image2','image3'];
  
    useEffect(() => {
      let timeoutId = setTimeout(() => {
        setImageIndex((imageIndex+1) %images.length);
      }, 2000);
      
      return () => {
        clearTimeout(timeoutId)
      }
    }, [imageIndex])

    return <h2>{images[imageIndex]}</h2>
  
}




ReactDOM.render(
  <Test/>,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>


<div id="root"></div>

Upvotes: 2

Related Questions