Next.js项目Apollo Client调用useQuery出现上下文未定义错误求助
Next.js + Apollo Client 报错:Cannot read properties of undefined (reading 'Symbol(APOLLO_CONTEXT)')
在Next.js项目中使用Apollo Client获取数据时触发报错,此前代码正常运行。已尝试删除node_modules重装、清除_next文件夹、更新npm包等常规方案,均未解决问题。
报错信息
Unhandled Runtime Error Error: Cannot read properties of undefined (reading 'Symbol(__APOLLO_CONTEXT__)')
报错栈详情
contextKey node_modules\@apollo\client\react\context\context.cjs (27:49) getApolloContext node_modules\@apollo\client\react\hooks\hooks.cjs (30:45) useApolloClient node_modules\@apollo\client\react\hooks\hooks.cjs (86:28) app\[blog]\page.jsx (32:44) @ result 30 | export default function Hakkimda({ params, launches }) { 31 | //console.log("launches", launches); > 32 | const { loading, error, data } = useQuery(result, client); | ^ 33 | 34 | if (loading) return <p>Loading...</p>; 35 | if (error) return <p>Error: {error.message}</p>; Call Stack type node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-server.edge.development.js (1447:17) attemptResolveElement node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-server.edge.development.js (1759:20) resolveModelToJSON node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-server.edge.development.js (1249:13) stringify <anonymous> stringify node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-server.edge.development.js (181:13) processModelChunk node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-server.edge.development.js (2062:25) retryTask node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-server.edge.development.js (2109:6) performWork node_modules\next\dist\compiled\react-server-dom-webpack\cjs\react-server-dom-webpack-server.edge.development.js (1544:13) listOnTimeout node:internal/timers (569:17) process.processTimers node:internal/timers (512:7)
相关代码文件
apolloclient.js
import { ApolloClient, ApolloProvider, InMemoryCache } from "@apollo/client"; const client = new ApolloClient({ uri: "https://api.mocki.io/v2/c4d7a195/graphql", cache: new InMemoryCache(), }); export default client;
页面代码(app[blog]\page.jsx)
import { gql, useQuery } from "@apollo/client"; import client from "../lib/apolloClient"; const GET_POSTS = gql` { users { ID e-mail name } } `; const result = await client.query({ query: gql` { users { ID e-mail name } } `, }); export default function Hakkimda({ params, launches }) { // console.log("launches", launches); const { loading, error, data } = useQuery(result, client); if (loading) return <p>Loading...</p>; if (error) return <p>Error: {error.message}</p>; return ( <main className="container min-h-screen px-8 mx-auto max-w-7xl"> <h1 className="mb-6 text-2xl capitalize">Incoming Parameter: {}</h1> <div></div> </main> ); } export async function getStaticProps() { return { props: { launches: [], }, }; }
package.json
{ "name": "salihonderfrontend", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint", "cache-clean": "npm cache clean --force && yarn cache clean" }, "dependencies": { "@apollo/client": "^3.7.14", "@fortawesome/free-brands-svg-icons": "^6.4.0", "@fortawesome/free-solid-svg-icons": "^6.4.0", "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^1.7.14", "@heroicons/react": "^2.0.17", "autoprefixer": "^10.4.14", "eslint": "^8.40.0", "eslint-config-next": "^13.4.1", "graphql": "^16.6.0", "next": "^13.4.1", "postcss": "^8.4.23", "react": "^18.2.0", "react-dom": "^18.2.0", "tailwindcss": "^3.3.2" }, "browser": { "fs": false, "os": false, "path": false } }
next.config.js
/** @type { import('next').NextConfig} */ const nextConfig = { //reactStrictMode: true, //swcMinify: true, experimental: { appDir: true, }, webpack: (config) => { config.experiments = config.experiments || {}; config.experiments.topLevelAwait = true; return config; }, }; module.exports = nextConfig;
问题分析与解决方案
核心问题
useQuery参数错误:useQuery第一个参数应为GraphQL查询文档(gql模板字符串),而非client.query()的返回结果;且无需手动传入client,组件被ApolloProvider包裹后会自动获取上下文。- 缺少ApolloProvider全局包裹:应用未被
ApolloProvider包裹,导致useQuery无法找到Apollo上下文,触发Symbol(__APOLLO_CONTEXT__)未定义报错。 - App Router不兼容
getStaticProps:当前使用Next.js 13 App Router(experimental.appDir: true),getStaticProps是Pages Router的API,在此无效。 - 组件外部top-level await违规:在组件模块顶部直接使用
await client.query()不符合React规范,会导致服务器渲染序列化问题。
具体修复步骤
1. 配置ApolloProvider根包裹
修改app/layout.jsx(App Router根布局文件),用ApolloProvider包裹整个应用:
import { ApolloProvider } from '@apollo/client'; import client from '../lib/apolloclient'; export default function RootLayout({ children }) { return ( <html lang="en"> <body> <ApolloProvider client={client}>{children}</ApolloProvider> </body> </html> ); }
2. 修正页面组件代码
移除组件外部的await client.query(),正确使用useQuery,并删除无效的getStaticProps:
import { gql, useQuery } from '@apollo/client'; const GET_POSTS = gql` { users { ID name "e-mail" # 字段含连字符,需用引号包裹 } } `; export default function Hakkimda({ params }) { const { loading, error, data } = useQuery(GET_POSTS); if (loading) return <p>Loading...</p>; if (error) return <p>Error: {error.message}</p>; return ( <main className="container min-h-screen px-8 mx-auto max-w-7xl"> <h1 className="mb-6 text-2xl capitalize">Incoming Parameter: {params.blog}</h1> <div> {data?.users?.map(user => ( <div key={user.ID}> <p>Name: {user.name}</p> <p>Email: {user["e-mail"]}</p> </div> ))} </div> </main> ); }
注意:GraphQL字段
user["e-mail"]访问,不能用user.e-mail。
3. 移除无效Webpack配置
在next.config.js中删除topLevelAwait配置:
/** @type { import('next').NextConfig} */ const nextConfig = { experimental: { appDir: true, }, }; module.exports = nextConfig;
4. 可选:服务器组件直接获取数据(推荐)
App Router中推荐用服务器组件直接调用client.query()获取数据,无需客户端请求:
import { gql } from '@apollo/client'; import client from '../lib/apolloclient'; const GET_POSTS = gql` { users { ID name "e-mail" } } `; export default async function Hakkimda({ params }) { const { data } = await client.query({ query: GET_POSTS }); return ( <main className="container min-h-screen px-8 mx-auto max-w-7xl"> <h1 className="mb-6 text-2xl capitalize">Incoming Parameter: {params.blog}</h1> <div> {data?.users?.map(user => ( <div key={user.ID}> <p>Name: {user.name}</p> <p>Email: {user["e-mail"]}</p> </div> ))} </div> </main> ); }
内容的提问来源于stack exchange,提问作者wplover
相关产品推荐
相关产品推荐

