You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 22:33:18