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.