How to cancel all subscriptions and asynchronous tasks in a useEffect cleanup function?

Even if the component is unmounted, useEffect will try to maintain contact with your data-fetching function. Because this is an anti-pattern that exposes your app to memory leaks, canceling your useEffect subscription optimizes your app.

When you don’t use you useEffect hook effectively and dont perform any cleanup technique then the error looks like in the console:

React Hook Warnings for async function in useEffect: useEffect function must return a cleanup function or nothing….

To fix this problem, given below some example code, that might be help:

Example Code(Solution-1):

In the simple implementation example below, you’d use a flag (such as, isSubscribed) to determine when to cancel your subscription. At the end of the effect, you’d make a call to clean up.

useEffect(() => {
  // set a clean up flag
  let isSubscribed = true;

  // Try to communicate with sever API
  fetch(SERVER_URI)
    .then(response => response.json())
    .then(data => isSubscribed ? setState(prevState => ({
      ...prevState, user: data
    })) : null)
    .catch(error => {
      if (isSubscribed) {
        setState(prevState => ({
          ...prevState,
          error
        }));
      }
    })

  // cancel subscription to useEffect
  return () => (isSubscribed = false)
}, []);

Example Code(Solution-2):

import React,{useEffect} from 'react';

const App = () => {
  const [ data, setData ] = React.useState([]);

useEffect(() => {
  const abortController = new AbortController();
  
  void async function fetchData() {
    try {
        const url = 'https://jsonplaceholder.typicode.com/todos/1';
        const response = await fetch(url, { signal: abortController.signal });
        setData(await response.json());
    } catch (error) {
        console.log('error', error);
    }
}();

  // cancel subscription to useEffect
  return () => {
    abortController.abort(); // cancel pending fetch request on component unmount
  }
}, []);

return <pre>{JSON.stringify(data, null, 2)}</pre>;

}

export default App

Example Code(Solution-3):

const [data, setData] = useState(null);
const [posts, setPosts] = useState(null);
/* This would be called on initial page load */
useEffect(()=>{
    fetch(`url`)
    .then(data => {
        setData(data);
    })
    .catch(err => {
        /* perform error handling if desired */
    });
}, [])

/* This would be called when store/state data is updated */
useEffect(()=>{
    if (data) {
        setPosts(data.children.map(it => {
            /* do what you want */
        }));
    }
}, [data]);

In this way you can easily handle this issue. Its very important to cancel all subscriptions and asynchronous tasks in a useEffect cleanup function. I Hope it will help! If any issues, let me know in the comment section.