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

Next.js使用useQuery遇异步组件不支持Hooks错误排查

问题分析与解决方案

核心错误原因

你遇到的Hooks are not supported inside an async component错误,根源在于React Hook的使用规则被违反:

  • usePathname是客户端Hook,只能在客户端组件的顶层作用域调用,不能放在普通async函数(如你的getData)中。
  • 你在服务器组件(Home,无"use client"指令)中调用了包含Hook的fetchData,服务器组件本身不允许使用任何Hook。

同时,你的代码还存在use client指令滥用、数据获取逻辑与Hook耦合、React Query配置缺失等问题,以下是分步修复方案:


步骤1:重构纯数据获取函数

将fetchData改为不依赖任何Hook的纯异步函数,接收lat和lon作为参数,避免与客户端Hook耦合:

// app/fetchData.jsx
async function fetchData(lat, lon) {
  const options = {
    method: "GET",
    headers: {
      accept: "application/json",
    },
  };

  try {
    const response = await fetch(
      `http://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${process.env.API_KEY}&units=imperial`,
      options
    );
    
    if (!response.ok) throw new Error('请求天气数据失败');
    return await response.json();
  } catch (err) {
    console.error(err);
    throw err; // 抛出错误让useQuery捕获并处理
  }
}

export default fetchData;

步骤2:修正客户端组件Temps

在Temps组件中直接使用useSearchParams获取URL参数,再传递给fetchData,同时修复条件渲染逻辑:

// components/Temps.jsx
"use client"

import { useQuery } from "@tanstack/react-query";
import fetchData from "../app/fetchData.jsx";
import { useSearchParams } from "next/navigation";

export default function Temps(){
  const searchParams = useSearchParams();
  const lat = searchParams.get('lat');
  const lon = searchParams.get('lon');

  const{ data, error, isError, isLoading } = useQuery({
    queryKey: ["wdata", lat, lon], // 将参数加入queryKey,参数变化时自动重新请求
    queryFn: () => fetchData(lat, lon),
    enabled: !!lat && !!lon, // 仅当lat和lon都存在时才发起请求
  });   

  if (isLoading) return <span>加载中...</span>;
  if (isError) return <span>错误: {error.message}</span>;
  if (!data) return null;

  return(
    <div>
      <p>{JSON.stringify(data)}</p> {/* 用JSON.stringify展示对象,避免[object Object] */}
    </div>
  )
}

步骤3:配置React Query全局Provider

React Query需要在客户端全局提供QueryClientProvider才能工作,修改根布局文件:

// app/layout.jsx
"use client"

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useState } from 'react';

export default function RootLayout({ children }) {
  // 初始化QueryClient,确保客户端只创建一次
  const [queryClient] = useState(() => new QueryClient());

  return (
    <html lang="zh-CN">
      <body>
        <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
      </body>
    </html>
  );
}

步骤4:简化Home服务器组件

移除Home中错误的预取逻辑,服务器组件无需直接操作React Query:

// app/page.jsx
import WeatherApp from './WeatherApp';
import Temps from '@/components/Temps';

export default function Home() {
  return (
    <div>
      <WeatherApp />
      <Temps />
    </div>
  );
}

关键概念澄清

  1. "use client"适用范围:

    • 仅在需要使用客户端API(如Hook、浏览器API)的组件顶部添加,纯数据获取函数、服务器组件不需要。
    • 加了该指令的组件会在客户端渲染,允许使用所有React Hook。
  2. async关键字的必要性:

    • 服务器组件可以是async,用于预取服务器端数据并渲染静态内容。
    • 客户端组件不建议设为async(除非配合React 18 Suspense),数据加载状态由useQuery等工具处理。
    • 数据获取函数必须是async,但不能在其中使用任何Hook。

内容的提问来源于stack exchange,提问作者Marco Antonio Martinez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 16:23:17