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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.20 06:14:32