解决ApolloError:未定义Fragment在client.query中的引入问题
问题背景
我在复杂项目中编写了如下代码:
import { gql } from '@apollo/client'; gql` fragment StuffTable on Stuff { id status } `; export const GetStuffDocument = gql` query GetStuff($id: ID!) { stuff(id: $id) { id ...StuffTable } } ` // 另一个文件中的代码: import { ApolloClient, useApolloClient } from '@apollo/client'; import GetStuffDocument from './OtherFile'; async function exportStuff(client: ApolloClient<unknown>): Promise<void> { const { data: metadata } = await client.query<GetStuffQuery>({ query: GetStuffDocument, }); // 其他逻辑,但在client.query步骤报错 } function MyComponent() { const client = useApolloClient(); return <button onClick={() => exportStuff(client)}>Download</button> }
错误场景
点击导出按钮获取GraphQL数据生成CSV时,手动调用client.query抛出错误:
Uncaught (in promise) Error: Fragment StuffTable was used, but not defined at new ApolloError (index.ts:54:1) at QueryManager.ts:1043:1 at both (asyncMap.ts:30:1) at asyncMap.ts:19:1 at new Promise (<anonymous>) at Object.then (asyncMap.ts:19:1) at Object.next (asyncMap.ts:31:1) at notifySubscription (module.js:132:1) at onNotify (module.js:176:1) at SubscriptionObserver.next (module.js:225:1)
疑问
我想知道如何在手动调用的client.query中引入该Fragment解决错误,能否用以下方式实现?
const StuffTableFragment = gql` fragment StuffTable on Stuff { id status } `; // 然后调用: const { data: metadata } = await client.query<GetStuffQuery>({ query: GetStuffDocument, fragments: [StuffTableFragment], });
查阅Apollo Client官方文档没找到相关帮助,特此求助。
首先明确:你尝试的fragments参数在Apollo Client的client.query配置中不存在,这种写法无效。
下面是几种可行的解决方法:
方法1:将Fragment与Query定义在同一个gql模板中
把Fragment直接包含在导出的Query文档里,这样Apollo Client能自动识别关联的Fragment:
import { gql } from '@apollo/client'; export const GetStuffDocument = gql` fragment StuffTable on Stuff { id status } query GetStuff($id: ID!) { stuff(id: $id) { id ...StuffTable } } `
这种方式最直接,确保Query和它依赖的Fragment被解析器同时处理。
方法2:导出Fragment并与Query合并
如果Fragment需要复用在多个Query中,可以单独导出Fragment,然后在调用client.query时,将Query和Fragment合并成一个完整的文档:
// 原文件中导出Fragment和Query import { gql } from '@apollo/client'; export const StuffTableFragment = gql` fragment StuffTable on Stuff { id status } `; export const GetStuffDocument = gql` query GetStuff($id: ID!) { stuff(id: $id) { id ...StuffTable } } `
// 在调用的文件中:
import { ApolloClient, useApolloClient, gql } from '@apollo/client';
import { GetStuffDocument, StuffTableFragment } from './OtherFile';
async function exportStuff(client: ApolloClient
// 合并Query和Fragment
const combinedQuery = gql ${StuffTableFragment} ${GetStuffDocument} ;
const { data: metadata } = await client.query
query: combinedQuery,
});
// 后续逻辑
}
## 方法3:在Apollo Client初始化时注册全局Fragment 如果Fragment会被多个地方频繁使用,可以在创建Apollo Client实例时,通过`typeDefs`注册全局Fragment: ```typescript import { ApolloClient, InMemoryCache, gql } from '@apollo/client'; const StuffTableFragment = gql` fragment StuffTable on Stuff { id status } `; const client = new ApolloClient({ uri: '你的GraphQL端点', cache: new InMemoryCache(), typeDefs: [StuffTableFragment], // 注册全局Fragment });
这样所有使用该Fragment的Query都能自动识别,无需每次合并。
为什么你的尝试无效?
Apollo Client的client.query方法的配置参数中没有fragments这个选项,官方也从未支持过这种写法。Fragment必须和Query一起被包含在同一个GraphQL文档中,或者通过全局注册让客户端能找到它。
内容的提问来源于stack exchange,提问作者Alien

