Next.js 14.2.3用Apollo Client调GraphQL API报useContext不可用错误
问题:Next.js 14.2.3 + Apollo Client 3.10.3 出现 "useContext 不可用" 错误
我搭建了Next.js 14.2.3应用,通过@apollo/client@3.10.3和graphql@16.8.1对接本地GraphQL API(地址http://localhost:8000/graphql/),并创建了pages/products页面。访问http://localhost:3000/products时,出现错误:
Error: React functionality 'useContext' is not available in this environment.
Products页面代码
import { useQuery, gql } from "@apollo/client"; import { initializeApollo } from "../lib/apollo-client"; const PRODUCTS_QUERY = gql` query Products { products(first: 10, channel: "default-channel") { edges { node { id name } } } } `; function Products() { const apolloClient = initializeApollo(); const { data, loading, error } = useQuery(PRODUCTS_QUERY, { client: apolloClient, }); if (loading) return <p>Loading...</p>; if (error) return <p>Error: {error.message}</p>; return ( <div> <h1>Products</h1> <ul> {data && data.products.edges.map(({ node }) => ( <li key={node.id}>{node.name}</li> ))} </ul> </div> ); } export default Products;
apollo-client.js代码
import { useMemo } from "react"; import { ApolloClient, HttpLink, InMemoryCache } from "@apollo/client"; let apolloClient; function createApolloClient() { return new ApolloClient({ ssrMode: typeof window === "undefined", link: new HttpLink({ uri: "http://localhost:8000/graphql/", }), cache: new InMemoryCache(), }); } export function initializeApollo(initialState = null) { const _apolloClient = apolloClient ?? createApolloClient(); // If your page has Next.js data fetching methods that use Apollo Client, the initial state gets hydrated here if (initialState) { _apolloClient.cache.restore(initialState); } // For SSG and SSR always create a new Apollo Client if (typeof window === "undefined") return _apolloClient; // Create the Apollo Client once in the client if (!apolloClient) apolloClient = _apolloClient; return _apolloClient; } export function useApollo(initialState) { const store = useMemo(() => initializeApollo(initialState), [initialState]); return store; }
错误原因
useQuery Hook内部默认依赖Apollo Client的Context Provider获取客户端实例,即便你手动传入client参数,它依然会尝试调用useContext做内部校验。在Next.js的SSR/SSG渲染流程中,组件可能在非React Context环境下执行,从而触发该错误。
解决方案
方案1:全局配置Apollo Provider
通过_app.js全局注入Apollo Client,让所有组件通过Context获取客户端实例:
- 修改
pages/_app.js(或_app.tsx):
import { ApolloProvider } from '@apollo/client'; import { useApollo } from '../lib/apollo-client'; export default function App({ Component, pageProps }) { const apolloClient = useApollo(pageProps.initialApolloState); return ( <ApolloProvider client={apolloClient}> <Component {...pageProps} /> </ApolloProvider> ); }
- 修改Products页面,移除手动创建客户端的代码:
import { useQuery, gql } from "@apollo/client"; const PRODUCTS_QUERY = gql` query Products { products(first: 10, channel: "default-channel") { edges { node { id name } } } } `; function Products() { const { data, loading, error } = useQuery(PRODUCTS_QUERY); if (loading) return <p>加载中...</p>; if (error) return <p>错误: {error.message}</p>; return ( <div> <h1>产品列表</h1> <ul> {data && data.products.edges.map(({ node }) => ( <li key={node.id}>{node.name}</li> ))} </ul> </div> ); } export default Products;
方案2:使用Next.js数据预取方法
如果不需要客户端实时查询,可通过getStaticProps或getServerSideProps在服务器端预取数据,再传递给组件:
import { initializeApollo } from "../lib/apollo-client"; import { gql } from "@apollo/client"; const PRODUCTS_QUERY = gql` query Products { products(first: 10, channel: "default-channel") { edges { node { id name } } } } `; function Products({ products }) { if (!products) return <p>加载中...</p>; return ( <div> <h1>产品列表</h1> <ul> {products.map(({ node }) => ( <li key={node.id}>{node.name}</li> ))} </ul> </div> ); } export async function getStaticProps() { const apolloClient = initializeApollo(); const { data } = await apolloClient.query({ query: PRODUCTS_QUERY }); return { props: { products: data.products.edges, initialApolloState: apolloClient.cache.extract(), }, revalidate: 60, // 可选,开启增量静态生成 }; } export default Products;
内容的提问来源于stack exchange,提问作者motivation Thoughts
相关产品推荐
相关产品推荐

