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

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获取客户端实例:

  1. 修改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>
  );
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 14:25:30