在getStaticProps中调用ApolloClient查询时触发无效Hook调用错误
解决Next.js getStaticProps中复用GraphQL查询的无效Hook调用问题
这个错误的根源很明确:你违反了React Hooks的核心规则——Hooks只能在函数组件的主体内部,或者自定义Hooks的顶层调用。而getStaticProps是Next.js提供的独立数据获取函数,它运行在构建阶段(或增量静态生成阶段),不属于React组件的渲染流程,完全没有React的上下文,所以肯定不能在这里使用useFetchHomeContentQuery这类自动生成的Hook。
下面给你一套完整的解决方案,既能实现查询逻辑的复用,又能彻底解决这个错误:
1. 先封装可复用的Apollo客户端实例
首先不要再在每个页面的getStaticProps里重复创建ApolloClient,单独新建一个文件统一管理:
// graphql/client.ts import { ApolloClient, InMemoryCache } from '@apollo/client'; // 只初始化一次客户端实例 const apolloClient = new ApolloClient({ uri: "https://my-graphql-domain.com/graphql", cache: new InMemoryCache(), }); export default apolloClient;
2. 基于自动生成的查询文档封装复用函数
自动生成的GraphQL代码里,会包含FetchHomeContentDocument这个查询文档(对应你之前手写的gql查询语句)。我们可以直接用这个文档,封装一个独立的异步查询函数,完全避开Hook:
// graphql/queries/home.ts import apolloClient from '../client'; // 导入自动生成的查询文档和类型定义 import { FetchHomeContentDocument, FetchHomeContentQuery } from './generated/graphql'; // 封装可复用的查询函数 export async function fetchHomeContent(): Promise<FetchHomeContentQuery> { const { data } = await apolloClient.query({ query: FetchHomeContentDocument, // 如果需要传变量,这里可以添加,比如: // variables: { id: "1" } }); return data; }
3. 在getStaticProps中调用这个复用函数
现在回到pages/index.tsx,直接调用封装好的查询函数即可,完全不需要Hook:
// pages/index.tsx import { fetchHomeContent } from '../graphql/queries/home'; export async function getStaticProps() { // 调用复用的查询逻辑 const data = await fetchHomeContent(); return { props: { data, }, }; }
为什么这个方案可行?
自动生成的useFetchHomeContentQuery本质是对Apollo客户端query方法的React Hook封装,它依赖React的组件状态和上下文来处理加载、错误等状态。但在getStaticProps里,我们只需要纯数据获取,不需要这些React相关的状态管理,直接调用底层的apolloClient.query方法就足够了。
这样做的好处:
- 避免了重复编写客户端初始化和查询代码,实现了逻辑复用
- 完全符合React Hooks的规则,不会再触发无效Hook调用的错误
- 客户端实例只初始化一次,减少了不必要的性能开销
内容的提问来源于stack exchange,提问作者Laurence Cope
相关产品推荐
相关产品推荐

