我想为我的项目做一个可重用的http钩子,并使用abortController作为清理函数。
import { useState, useEffect } from 'react';
const useHttp = (url = {}, opts = {}) => {
const [resData, setResData] = useState(null);
const [error, setError] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [status, setStatus] = useState(null);
useEffect(() => {
if (url === '') return;
const controller = new AbortController();
const { signal } = controller;
setIsLoading(true);
const fetchData = async () => {
try {
const response = await fetch(url, {
method: opts.method || 'GET',
body: opts.body || undefined,
headers: opts.headers || {
'Content-Type': 'application/json',
},
credentials: 'include',
signal,
});
const data = await response.json();
console.log(data);
const resStatus = response.status;
// setResData(data);
setError(null);
setIsLoading(false);
setStatus(resStatus);
} catch (err) {
// setResData(null);
setError(err);
setIsLoading(false);
setStatus(500);
}
};
fetchData();
return () => {
controller.abort();
};
}, [url, opts]);
return { resData, error, isLoading, status };
};
export default useHttp;
我发现只有在设置resData状态时才会发生无限循环,但我不知道为什么。
因为我发现很多例子里面也设置了respsonse状态的数据钩子。
有人能给我指出来吗?
2条答案
按热度按时间hjqgdpho1#
我认为问题在于
url
和opts
默认为{}
。例如,与字符串相比,
"" === "" -> true
对象通过引用进行比较,因此{} === {} -> false
。在您的情况下,这意味着要React的url
和opts
在每次渲染时都不同,这将导致useEffect
在每次渲染时运行。作为一个修正,我建议你删除
url
和opts
的默认值,并允许它们为undefined
。由于undefined === undefined -> true
,useEffect
将只运行一次。如果你想保留默认值,另一个可行的方法是声明一次,然后重用那个值,这样React就会注意到这个值是相同的。
yruzcnhs2#
发生这种情况是因为当在这个定制钩子(useHttp)中设置状态时,组件将在您使用这个useHttp钩子的地方重新呈现。
然后这个组件会再次触发
useHttp
钩子,重新运行等等,这就导致了无限循环。