我正在尝试创建一个'useApi'钩子,它接受一个返回promise的函数。在我当前的实现中,我收到了关于在useEffect钩子中不包括依赖项的警告,即我传递给它的API promise函数。然而,如果我将其包括在依赖项中,它会导致无限循环。
我看了很多问题,但似乎解决不了。
请在这里找到我的样本:Codesandbox
问题是fetchData
函数有两个依赖项,它们一直在变化:state
和apiCall
。
state
一直在更改,因为您更新了fetchData
函数本身内部的状态
问题的解决方案是从setState
函数本身获得状态,如下所示:
const fetchData = React.useCallback(() => {
setState((state) => {
return { ...state, loading: true, response: undefined };
});
apiCall()
.then((response) => {
setState((state) => {
return { ...state, response, loading: false };
});
})
.catch((err) => {
setState({ loading: false, response: undefined, error: err });
});
}, [apiCall]);
通过这种方式,您可以删除state
依赖项。
apiCall
也一直在变化,因为每次重新渲染组件时都会重新创建函数
要解决此问题,需要将useApi
回调封装在useCallback
钩子中:
const [{ error, loading, response }, fetchData, reset] = useApi(
React.useCallback(() => randomNumberApi(max), [max])
);
现在,您可以在不引起无限循环的情况下拥有useEffect
依赖项:
React.useEffect(() => {
if (max) {
fetchData();
}
}, [fetchData, max]);
完整代码的CodeSandbox。
Ciao,要删除警告,只需要删除useEffect
上的括号,如:
React.useEffect(() => {
if (max) {
fetchData();
}
}); // remove brackets
现在的问题是,每当App.js更改其状态时,都会调用useEffect
(我的意思是总是这样,因为fetchData
更改了App.js的状态(,结果是一个无限循环。
为了解决这个问题,你可以用这种方式使用useRef
:
import React, { useRef } from "react";
...
const firstLoad = useRef(true);
React.useEffect(() => {
if (max && firstLoad.current) {
fetchData();
}
firstLoad.current = false;
});
并且fetchData()
将仅被调用一次(在第一次加载时(。
这里修改了你的代码沙盒。