请耐心等待,因为这个答案很长。
我也遇到了这个问题。问题似乎发生在使用片段(在这种情况下,内联)和接口时。我设法通过将正确的内省数据传递给 Apollo 的启发式片段匹配器来解决它(参见步骤 3)。
这是有关如何解决此问题的详细分步指南:
1 - 验证控制台警告。
验证您的控制台中是否有警告(这是一个发生在我身上的示例)。这些是与默认启发式片段匹配器冲突的字段:
阅读 Apollo 文档,我发现了以下内容:
默认情况下,Apollo Client 的缓存将使用启发式片段匹配器,它假设如果结果包含其选择集中的所有字段,则该片段匹配,并且在缺少任何字段时不匹配。这在大多数情况下都有效,但这也意味着 Apollo Client 无法为您检查服务器响应,并且无法告诉您何时使用 update、updateQuery、writeQuery 等手动将无效数据写入存储。此外,启发式使用带有联合或接口的片段时,片段匹配器将无法准确工作. 如果 Apollo 客户端尝试使用带有联合/接口的默认启发式片段匹配器,它会通过控制台警告(正在开发中)让您知道这一点。IntrospectionFragmentMatcher 是使用联合/接口的解决方案,下面有更详细的解释。
有关 v2 的更多信息,请访问:https :
//www.apollographql.com/docs/react/v2.6/data/fragments/#fragments-on-unions-and-interfaces
有关 v3 的更多信息,请访问:https :
//www.apollographql.com/docs/react/data/fragments/#using-fragments-with-unions-and-interfaces
为了解决这个问题,我们需要将 IntrospectionResultData 传递给 Apollo 客户端(参见步骤 3)。但在此之前,我们需要生成文件或数据。
您有 3 个选择。手动或自动(远程或本地)执行此操作。
2 - 生成内省文件
挑选一个下面的选项(所有的人最终会被相同)。在选择一个之前阅读所有这些。
2.1 - 选项 A - 手动生成文件。
使用以下模式使其适应您自己的模式。注意,以下是 TypeScript 代码。type
如果您使用的是普通 JS,请删除。
请注意,在我的情况下,我的 .gql 文件中有以下方式的联合类型:
# GraphQL code omitted.
union PlanningResult = Planning | PlanningTechnical
// For Apollo V 2.x
export interface IntrospectionResultData {
__schema: {
types: {
kind: string;
name: string;
possibleTypes: {
name: string;
}[];
}[];
};
}
const result: IntrospectionResultData = {
__schema: {
types: [
{
kind: 'UNION',
name: 'PlanningResult',
possibleTypes: [
{
name: 'Planning',
},
{
name: 'PlanningTechnical',
},
],
},
],
},
};
export default result;
// For Apollo V3:
export interface PossibleTypesResultData {
possibleTypes: {
[key: string]: string[]
}
}
const result: PossibleTypesResultData = {
"possibleTypes": {
"PlanningResult": [
"Planning",
"PlanningTechnical"
]
}
};
export default result;
完成此操作后,继续执行步骤 3。
2.2 - 选项 B - 自动远程进近。
这是如果您在远程服务器中拥有架构并且想要获取它。这是直接从 Apollo Docs 中提取的脚本。对于自动方法,您可以按照 Apollo Docs 中的说明直接获取架构:
// This is for V2 only, for V3 use the link down below (They're not the same!).
// For V2: https://www.apollographql.com/docs/react/v2.6/data/fragments/#fragments-on-unions-and-interfaces
// For V3 please, go to https://www.apollographql.com/docs/react/data/fragments/#generating-possibletypes-automatically
const fetch = require('node-fetch');
const fs = require('fs');
fetch(`${YOUR_API_HOST}/graphql`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
variables: {},
query: `
{
__schema {
types {
kind
name
possibleTypes {
name
}
}
}
}
`,
}),
})
.then(result => result.json())
.then(result => {
// here we're filtering out any type information unrelated to unions or interfaces
const filteredData = result.data.__schema.types.filter(
type => type.possibleTypes !== null,
);
result.data.__schema.types = filteredData;
fs.writeFile('./fragmentTypes.json', JSON.stringify(result.data), err => {
if (err) {
console.error('Error writing fragmentTypes file', err);
} else {
console.log('Fragment types successfully extracted!');
}
});
});
这将生成一个具有__schema
适当类型的 json 文件。完成此操作后,继续执行步骤 3。
2.3 - 选项 C - 自动本地方法
上面的选项对我来说很难,因为我的架构在身份验证墙后面。幸运的是,我确实可以直接在本地访问 .gql 文件,并且能够生成自省文件。继续阅读:
我们用来graphql-code-generator
为我们生成内省文件。
转到您的后端代码,或您的 graphql.gql 文件所在的任何位置,然后执行以下操作:
- 安装GraphQL 代码生成器:
yarn add graphql
yarn add -D @graphql-codegen/cli
- 运行初始化向导:
yarn graphql-codegen init
- 填写详细信息(适应您自己的情况)就我而言,我选择了:
- 后端 - API 或服务器,使用 React 构建的应用程序
- 你的架构在哪里?./appsync/appSync.gql
- 选择插件:Fragment Matcher(也可以随意选择其他插件......这是重要的一个!)
- 文档:./appsync/generated/introspection.ts(这是你想要输出文件的地方)
这将生成一个codegen.yml
包含插件和graphql-code-generator
运行配置的文件。
这是我的:
overwrite: true
schema: "./appsync/appSync.gql"
# documents: "./appsync/**/*.gql"
generates:
./appsync/generated/introspection.ts:
plugins:
# - "typescript"
# - "typescript-operations"
# - "typescript-resolvers"
# - "typescript-react-apollo"
- "fragment-matcher"
config:
# NOTE: Remember to specify the CORRECT Apollo Client Version
apolloClientVersion: 2.6
./graphql.schema.json:
plugins:
- "introspection"
我已经评论了对我们的任务不重要的部分。
然后(非常重要!)运行:
yarn install
因为向导将包添加到我们的package.json
.
然后,生成代码:
yarn generate
这将输出需要包含在 Apollo 中才能继续的 introspection.ts 文件。
3 - 将内省文件注入 ApolloClient
现在,在您的前端代码中,将introspection.ts
文件复制到您的存储库(如果它还没有在那里),并包含它:
注意:我已将我的文件重命名为 fragmentTypes.ts 并将其包含在 apollo 文件夹中:
For V2:
import ApolloClient from 'apollo-client/ApolloClient';
import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import { InMemoryCache } from 'apollo-cache-inmemory/lib/inMemoryCache';
// The file we just generated. If it's a .json file
// remember to include the .json extension
import introspectionQueryResultData from './apollo/fragmentTypes';
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData,
});
export const globalClient = new ApolloClient({
link,
cache: new InMemoryCache({ fragmentMatcher }),
});
For V3:
import { InMemoryCache, ApolloClient } from '@apollo/client';
// In case you used graphql-code-generator
// import introspectionQueryResultData from './apollo/fragmentTypes';
// The file we just generated. If it's a .json file
// remember to include the .json extension
import possibleTypes from './path/to/possibleTypes.json';
const cache = new InMemoryCache({
possibleTypes,
});
const client = new ApolloClient({
// ...other arguments...
cache,
});
在此之后,您的控制台警告应该消失,查询和突变应该正常执行。