Next.js构建报错:预渲染页面时React-Query未设置QueryClient的解决方法
解决Next.js构建时React-Query的"No QueryClient set"错误
问题背景
使用Next.js结合React-Query实现用户鉴权的useUser Hook,开发环境运行正常,但执行npm run build时触发预渲染报错:No QueryClient set, use QueryClientProvider to set one,取消index.tsx中useUser相关代码的注释后就会出现该错误。
问题原因
- 预渲染阶段缺少QueryClient上下文:Next.js的静态生成(SSG)或服务器端渲染(SSR)过程中,组件在服务器端执行,但全局未通过
QueryClientProvider提供QueryClient实例,导致useQuery无法找到所需上下文。 - 依赖版本冲突:项目同时安装了旧版
react-query@3.x和新版@tanstack/react-query@4.x,两者API和包结构不兼容,引发上下文识别异常。
解决方案
1. 清理依赖冲突
先卸载旧版React Query及对应类型定义,确保仅保留新版@tanstack/react-query:
npm uninstall react-query @types/react-query
后续代码统一使用@tanstack/react-query的v4版本API。
2. 全局配置QueryClientProvider
在Next.js的_app.tsx中包裹整个应用,提供全局的QueryClient实例,同时区分客户端与服务器端实例,避免 hydration 错误:
import { AppProps } from 'next/app'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { useState } from 'react'; export default function MyApp({ Component, pageProps }: AppProps) { // 仅在客户端初始化QueryClient,防止服务器端重复创建 const [queryClient] = useState(() => new QueryClient({ defaultOptions: { queries: { refetchOnWindowFocus: false, // 根据需求调整缓存策略 retry: 0, }, }, })); return ( <QueryClientProvider client={queryClient}> <Component {...pageProps} /> </QueryClientProvider> ); }
3. 优化useUser Hook的客户端执行逻辑
修改useUser.tsx,确保查询仅在客户端执行,避免服务器端预渲染时触发错误:
import { useQuery } from '@tanstack/react-query'; import { useState, useEffect } from 'react'; import Router from 'next/router'; interface IParams { redirectTo?: string; redirectIfFound?: boolean; } // 你的鉴权逻辑函数 const isAuthed = async () => { const res = await fetch('/api/auth/check'); return res.json(); }; const useUser = ({ redirectTo, redirectIfFound }: IParams) => { const isClient = typeof window !== 'undefined'; // 仅在客户端启用查询,避免服务器端预渲染报错 const { data, error } = useQuery(["authed"], isAuthed, { enabled: isClient, }); const [calledPush, setCalledPush] = useState(false); const user = data?.data; const hasUser = user; useEffect(() => { if (!redirectTo || !isClient) return; if ((redirectTo && !redirectIfFound && !hasUser) || (redirectIfFound && hasUser)) { let calledPushLatest; setCalledPush((latest) => { calledPushLatest = latest; return latest; }); if (calledPushLatest) return; setCalledPush(true); Router.push(redirectTo); } }, [redirectTo, redirectIfFound, hasUser, isClient]); return error ? null : user; }; export default useUser;
4. 验证构建
执行npm run build,确认报错消失,构建流程正常完成。
内容的提问来源于stack exchange,提问作者김정수
相关产品推荐
相关产品推荐

