React自定义Hook结合React Query使用时触发Invalid hook call错误求助
React自定义Hook结合React Query使用时触发Invalid hook call错误求助
嘿,我一眼就看出问题所在啦——你违反了React Hooks的核心规则!
你现在是在handleAssetId这个点击事件处理函数里调用getAssetData这个自定义Hook,但React明确要求:Hooks只能在函数组件的顶层作用域,或者其他自定义Hook的顶层调用,绝对不能放在事件处理、循环、条件判断这类嵌套逻辑里,这就是你触发Invalid hook call错误的根本原因。
下面给你一套完整的修复方案,既满足你“点击按钮才触发API请求”的需求,又完全符合Hook规则:
第一步:重构自定义Hook,让它专注于查询逻辑
把原来的getAssetData改成纯逻辑的自定义Hook,不要在Hook里处理渲染逻辑,也不要返回JSX,只封装React Query的查询逻辑:
// TestC.tsx import { useQuery } from "@tanstack/react-query"; import { getAssIdKey1 } from "./api/getassid_key1"; interface Data { id: string; hexstr: string; bytes: number[]; } export const useAssetData = () => { return useQuery<Data>({ queryKey: ["assetid2"], queryFn: getAssIdKey1, // 注意:你的接口返回是单个对象,所以placeholderData不用数组 placeholderData: { id: "dffd", hexstr: "0x1234", bytes: [] }, enabled: false, // 关键设置:禁止自动执行查询,等待手动触发 }); };
第二步:在App组件里正确使用Hook和触发请求
在组件的顶层调用自定义Hook,然后在点击事件里通过refetch方法手动触发API请求,把渲染逻辑单独抽出来:
// App.tsx import { useState } from 'react' import reactLogo from './assets/react.svg' import viteLogo from '/vite.svg' import './App.css' import { useAssetData } from "./TestC"; function App() { const [count, setCount] = useState(0) // 必须在组件顶层调用Hook,符合规则 const { data, status, error, refetch } = useAssetData(); // 点击按钮时,调用refetch触发API请求 const handleAssetId = () => { refetch(); }; // 单独抽离渲染数据的逻辑,保持组件结构清晰 const renderAssetContent = () => { if (status === "loading") return <h1>Loading...</h1>; if (status === "error") return <h1>Error: {error?.message}</h1>; if (!data) return null; return ( <div> <h1>AssetId Key 1</h1> <ol> <li>AssetId: {data.hexstr}</li> </ol> </div> ); }; return ( <div className="container"> <h1 className="title"> ReactJS (Vite) Quick Start </h1> <div> <button onClick={handleAssetId}> 获取AssetId </button> {/* 渲染获取到的资产数据 */} {renderAssetContent()} </div> </div> ); } export default App;
关键知识点解释
enabled: false:这个配置让React Query不会在组件挂载时自动发起请求,只有当你调用refetch()或者把enabled设为true时,才会执行API调用,完美匹配你“点击按钮才触发”的需求。- 为什么不能在事件里调用Hook?React依赖Hook的调用顺序来维护状态,如果在嵌套逻辑里调用Hook,会破坏这个顺序,导致状态管理混乱,所以这是硬性规则。
- 自定义Hook的设计原则:应该专注于封装可复用的状态逻辑,而不是处理渲染,渲染逻辑应该放在组件里完成。
这样修改后,你既可以通过按钮控制API请求的时机,又能正常使用React Query的缓存、重试等功能,还完全符合React的Hook规则~
备注:内容来源于stack exchange,提问作者frustrated
相关产品推荐
相关产品推荐

