React Query点击事件调用自定义Hook报错及数据查询方式咨询
问题解决与答疑
一、Hook调用报错的解决方法
你遇到的Invalid hook call错误,根源是React Hook的核心规则:所有Hook(包括自定义Hook)必须在函数组件的顶层作用域调用,不能放在事件处理函数、条件判断、循环这类嵌套逻辑里。你的useGuestInfo是自定义Hook,却在onGuestUpdate点击事件函数里调用,直接违反了规则。
下面给两种可行的解决方案:
方案1:调整自定义Hook,依赖参数自动触发查询
修改自定义Hook,让它接收bookingId作为参数,通过enabled控制查询时机,然后在组件顶层调用Hook,当bookingId变化时自动重新查询:
// 修改后的自定义Hook export const useGuestInfo = (bookingId) => { const { isLoading: isGettingGuestInfo, data: guestInfo } = useQuery({ queryKey: [`guest`, bookingId], // bookingId变化时,自动触发新查询 queryFn: () => getGuestInformation(bookingId), enabled: !!bookingId, // 只有当bookingId存在时才执行查询 }); return { isGettingGuestInfo, guestInfo }; };
组件中使用示例:
import { useSearchParams, useState } from "react"; import { useGuestInfo } from "./your-hook-path"; const YourComponent = () => { const [searchParams, setSearchParams] = useSearchParams(); const [updateGuestModal, setUpdateGuestModal] = useState(false); // 从URL参数取bookingId,组件顶层调用Hook const currentBookingId = searchParams.get("bookingId"); const { isGettingGuestInfo, guestInfo } = useGuestInfo(currentBookingId); const onGuestUpdate = () => { setUpdateGuestModal(true); // 更新URL参数里的bookingId searchParams.set("bookingId", bookingId); // 这里的bookingId是目标ID setSearchParams(searchParams); // 无需在这里调用Hook:URL参数更新后组件重新渲染,Hook会自动用新的bookingId查询数据 }; return ( <div> <button onClick={onGuestUpdate}>打开客人信息模态框</button> {updateGuestModal && ( <div className="modal"> {isGettingGuestInfo ? "加载中..." : <div>{guestInfo?.name}</div>} </div> )} </div> ); };
方案2:用QueryClient手动触发查询
如果不想依赖URL参数变化,想直接在事件里手动触发查询,可以用React Query的useQueryClient工具:
import { useQueryClient, useState, useSearchParams } from "react"; const YourComponent = () => { const queryClient = useQueryClient(); const [updateGuestModal, setUpdateGuestModal] = useState(false); const [searchParams, setSearchParams] = useSearchParams(); const [guestInfo, setGuestInfo] = useState(null); const [isLoading, setIsLoading] = useState(false); const onGuestUpdate = async () => { setUpdateGuestModal(true); searchParams.set("bookingId", bookingId); setSearchParams(searchParams); setIsLoading(true); try { // 手动调用查询,数据自动存入React Query缓存 const info = await queryClient.fetchQuery({ queryKey: [`guest`, bookingId], queryFn: () => getGuestInformation(bookingId), }); setGuestInfo(info); } catch (err) { console.error("获取数据失败:", err); } finally { setIsLoading(false); } }; return ( // 组件内容与方案1类似 ); };
二、是否必须用useQuery获取数据?
完全不是必须的,你可以用普通函数实现数据获取。
React Query的作用是帮你简化数据获取的缓存、状态管理、重复请求拦截等复杂逻辑,比如:
- 自动缓存相同请求的结果,避免重复调用API
- 自动管理加载、错误、成功状态
- 支持背景刷新、数据过期等高级功能
如果需求简单,只需要单次获取数据,用普通的async/await结合fetch或axios就足够了,示例如下:
// 普通API请求函数 const getGuestInformation = async (bookingId) => { const res = await fetch(`/api/guests/${bookingId}`); if (!res.ok) throw new Error("请求失败"); return res.json(); }; // 事件处理函数中调用 const onGuestUpdate = async () => { setUpdateGuestModal(true); searchParams.set("bookingId", bookingId); setSearchParams(searchParams); setIsLoading(true); try { const info = await getGuestInformation(bookingId); setGuestInfo(info); } catch (err) { alert("获取客人信息失败:" + err.message); } finally { setIsLoading(false); } };
这种方式需要你手动管理加载状态、错误处理,若需缓存还要自己写逻辑。如果项目有大量数据获取场景,React Query能省很多代码;但简单场景下,普通函数完全够用。
内容的提问来源于stack exchange,提问作者LightSkyLiam
相关产品推荐
相关产品推荐

