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> ); }
关键概念澄清
"use client"适用范围:- 仅在需要使用客户端API(如Hook、浏览器API)的组件顶部添加,纯数据获取函数、服务器组件不需要。
- 加了该指令的组件会在客户端渲染,允许使用所有React Hook。
async关键字的必要性:- 服务器组件可以是
async,用于预取服务器端数据并渲染静态内容。 - 客户端组件不建议设为
async(除非配合React 18 Suspense),数据加载状态由useQuery等工具处理。 - 数据获取函数必须是
async,但不能在其中使用任何Hook。
- 服务器组件可以是
内容的提问来源于stack exchange,提问作者Marco Antonio Martinez
相关产品推荐
相关产品推荐

