我尝试在useEffect调用中使用一个钩子,以便只运行一次(并加载一些数据)。我一直收到无法执行此操作的错误(尽管我在另一个应用程序中做了完全相同的事情,不知道为什么一个工作,另一个不工作),我知道我可能打破了挂钩规则...所以,我的目标是将所有的CRUD操作逻辑卸载到一个简单的钩子中。下面是MenuItem,它是尝试使用钩子获取数据的组件。
const MenuItem = () => {
const [ID, setID] = useState<number | null>(null);
const [menu, setMenu] = useState<Item[]>([]);
const { getMenu, retrievedData } = useMenu();
//gets menu items using menu-hook
useEffect(() => {
getMenu();
}, []);
//if menu is retrieved, setMenu to retrieved data
useEffect(() => {
if (retrievedData.length) setMenu(retrievedData);
}, []);
//onClick of menu item, displays menu item description
const itemHandler = (item: Item) => {
if (ID === null || ID !== item._id) {
setID(item._id);
} else {
setID(null);
}
};
return ...
};
下面是getMenu,它是处理逻辑和数据检索的自定义钩子。
const useMenu = () => {
const backendURL: string = 'https://localhost:3001/api/menu';
const [retrievedData, setRetrievedData] = useState<Item[]>([]);
const getMenu = async () => {
await axios
.get(backendURL)
.then((fetchedData) => {
setRetrievedData(fetchedData.data.menu);
})
.catch((error: Error) => {
console.log(error);
setRetrievedData([]);
});
};
return { getMenu, retrievedData };
};
export default useMenu;
最后是错误。
Invalid hook call. Hooks can only be called inside of the body of a function component.
我想补充的是,我也在使用Typescript,它现在没有抱怨。
2条答案
按热度按时间gxwragnw1#
你可以做一些事情来改进这段代码,这对将来可能会有帮助。你是对的,你打破了钩子的规则,但是没有必要!如果你把
fetch
移出钩子(没有必要在每次渲染时重新定义它),那么它不存在于deps
数组中是有效的,因为它是一个常量。我还会让您的
useMenu
钩子为您处理加载/返回加载值的所有细节。现在您可以使用钩子:
还有几件事-
react-query
是一个很好的例子,因为它将管理外部数据的所有生命周期/状态管理useMenu
钩子:现在来吃这个钩子:
useAsync
不仅能够在钩子提取时显示加载指示符,而且如果在async函数完成加载之前卸载了组件(上面的代码没有处理),useAsync
也不会给您发出内存泄漏警告。jv4diomz2#
在这个项目上工作了一段时间后,我也发现了另一个干净的解决方案,我相信它不会破坏钩子的规则。这需要我设置一个自定义的http钩子,它使用一个
sendRequest
函数来处理应用程序范围内的请求。让我澄清一下,这不是一个简单的解决方案,我确实增加了复杂性,但我相信它会有所帮助,因为我将在应用程序中发出多种不同类型的请求。这是新的useMenu钩子,注意我不需要返回getMenu,因为每次在我的应用中使用sendRequest时,都会自动调用getMenu。
祝你好运