嗨,我创建了一个React钩子来处理Axios请求。我遇到的问题是,我无法成功地中止请求以防止内存泄漏。当我在两个使用钩子的页面之间切换时,我得到错误:
无法在未挂载的组件上执行React状态更新。这是无操作,但它表明应用程序中存在内存泄漏。修复,在useEffect清理中取消所有订阅和异步任务函数。
useAxios钩子代码:
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;
您的setError
和setLoading
在中止时都将触发。
所以你需要在卸载回调中设置一个标志。然后,您可以有条件地基于此调用setError
/setLoading
。
useEffect(() => {
let aborting = false;
try {
....
} catch (err) {
console.log(err.message);
if (!aborting) {
setError(err.message);
setLoading(false);
}
}
....
return () => {
aborting = true;
controller.abort();
}
}, ...
防止内存泄漏
请注意,这实际上并不是内存泄漏,它只是一个可能来自内存泄漏的警告。如。使用addEventListener
而不使用removeEventListener
但是在任何一种情况下,您仍然希望在已挂载的组件上防止setState
。