How to cancel asynchronous tasks in a useEffect cleanup function?

Viewed 38

I am getting this error:

index.js:1 Warning: 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 a useEffect cleanup function. index.js:1 Warning: 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 a useEffect cleanup function. at Products (http://localhost:3000/static/js/main.chunk.js:2779:5) at div at Home at RenderedRoute (http://localhost:3000/static/js/vendors~main.chunk.js:246119:5) at Routes (http://localhost:3000/static/js/vendors~main.chunk.js:246568:5) at Router (http://localhost:3000/static/js/vendors~main.chunk.js:246499:15) at BrowserRouter (http://localhost:3000/static/js/vendors~main.chunk.js:244709:5) at div at App

I assume the problem is here:

Products.js

const [products, setProducts] = useState([]);

useEffect(() => {
    const getProdcuts = async () => {
      try {
        const res = await axios.get(
          category
            ? `http://localhost:5000/e-mart/products?category=${category}`
            : `http://localhost:5000/e-mart/products`
        );
        setProducts(res.data);
      } catch (err) {
        console.log(err.message);
      }
    };
    getProdcuts();
  }, [category]);

My home page is not loading. No problem is shown in the terminal. How can I resolve this?

1 Answers

You can use the AbortController to abort an async request, it'd look like

useEffect(() => {
    const abortController = new AbortController();
    const getProdcuts = async () => {
      try {
        const res = await axios.get(
          category
            ? `http://localhost:5000/e-mart/products?category=${category}`
            : `http://localhost:5000/e-mart/products`,
          { signal: abortController .signal } // Notice this line here
        );
        setProducts(res.data);
      } catch (err) {
        console.log(err.message);
      }
    };
    getProdcuts();

    return () => {
      // Function returned from useEffect is called on unmount
      // Here it'll abort the fetch
      abortController.abort(); 
    }

  }, [category]);

That's a quick way to fix this problem but if you're not sure why this problem is happening in the first place it's probably because you're not expecting Products to unmount. You might have a parent component rendering Products or one of its parents conditionnally and a state change cause an unmount before fetch is done.

Related