Hi I created a React hook to handle Axios requests. The trouble I'm having is that I'm unable to successfully abort the request to prevent memory leak. When I switch between 2 pages that uses the hook, I get error:
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.
useAxios hook code:
import { useState, useEffect } from "react";
import axios from "axios";
const useAxios = (url, method = "GET") => {
const [data, setData] = useState([]);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const [body, setBody] = useState(null);
useEffect(() => {
const controller = new AbortController();
const getData = async (body) => {
setLoading(true);
try {
const res = body
? await axios.post(url, body, {
signal: controller.signal,
})
: await axios.get(url, {
signal: controller.signal,
});
setData(res.data);
setError(null);
setLoading(false);
} catch (err) {
console.log(err.message);
setError(err.message);
setLoading(false);
}
};
if (method === "GET") {
getData();
} else if (method === "POST") {
getData(body);
}
return () => {
controller.abort();
};
}, [url, method, body]);
return { data, error, loading, setBody };
};
export default useAxios;
Your setError and setLoading are both going to fire when aborting.
So you will want to set a flag in the unmount callback.
You can then conditionally call setError / setLoading based on this.
useEffect(() => {
let aborting = false;
try {
....
} catch (err) {
console.log(err.message);
if (!aborting) {
setError(err.message);
setLoading(false);
}
}
....
return () => {
aborting = true;
controller.abort();
}
}, ...
prevent memory leak
Just a note, this wound't actually be a memory leak, it's just a warning that it could have come from one. eg. using addEventListener without removeEventListener. But in either case you would still want to prevent a setState on a umounted component.