Apollo 将第一个结果复制到边缘数组中的每个节点
Apollo duplicates first result to every node in array of edges
我正在使用 react-apollo 开发一个 React 应用程序
当我检查浏览器网络选项卡响应时通过 graphql 调用数据它显示数组的所有元素不同
但是我在我的应用程序中得到或 console.log()
然后数组的所有元素与第一个元素相同。
我不知道如何解决请帮助
将此放入您的 App.js
cache: new InMemoryCache({
dataIdFromObject: o => o.id ? `${o.__typename}-${o.id}` : `${o.__typename}-${o.cursor}`,
})
发生这种情况的原因是数组中的项目 "normalized" 与 Apollo 缓存中的值相同。 AKA,它们在阿波罗看来是一样的。这通常是因为它们共享相同的 Symbol(id)
.
如果你打印出你的 Apollo 响应对象,你会注意到每个对象都有 Symbol(id)
,它被 Apollo 缓存使用。您的数组项可能具有相同的 Symbol(id)
,这会导致它们重复。为什么会这样?
默认情况下,Apollo 缓存运行此 function 进行规范化。
export function defaultDataIdFromObject(result: any): string | null {
if (result.__typename) {
if (result.id !== undefined) {
return `${result.__typename}:${result.id}`;
}
if (result._id !== undefined) {
return `${result.__typename}:${result._id}`;
}
}
return null;
}
您的数组项目属性导致多个项目 return 相同的数据 ID。在我的例子中,多个项目有 _id = null
导致所有这些项目被重复。当这个函数 return 为 null 时 docs 说
InMemoryCache will fall back to the path to the object in the query,
such as ROOT_QUERY.allPeople.0 for the first record returned on the
allPeople root query.
当我们的数组项不能很好地与 defaultDataIdFromObject
一起工作时,这是我们真正想要的行为。
因此,解决方案是使用传递给 ApolloClient
中的 InMemoryCache
构造函数的 dataIdFromObject
选项手动配置这些唯一标识符。以下对我有用,因为我所有的对象都使用 _id 并且有 __typename.
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache({
dataIdFromObject: o => (o._id ? `${o.__typename}:${o._id}`: null),
})
});
我认为应避免使用其他两个答案中的方法,而应采用以下方法:
其实很简单。要了解它是如何工作的,只需按如下方式记录 obj:
dataIdFromObject: (obj) => {
let id = defaultDataIdFromObject(obj);
console.log('defaultDataIdFromObject OBJ ID', obj, id);
}
如果遇到此问题,您会在日志中看到 id 将为空。
注意记录'obj'。将为返回的每个对象打印它。
这些对象是 Apollo 试图从中获取唯一 ID 的对象(您必须告诉 Apollo 对象中的哪个字段对于从 GraphQL 返回的 'items' 数组中的每个对象都是唯一的 - 相同当您使用 'map' 或渲染 DOM 元素时的其他迭代时,您在 React 中为 'key' 传递唯一值的方式。
By default, InMemoryCache will attempt to use the commonly found
primary keys of id and _id for the unique identifier if they exist
along with __typename on an object.
因此请查看 'defaultDataIdFromObject ' 使用的记录 'obj' - 如果您没有看到 'id' 或“_id”,那么您应该在您的对象中提供唯一的字段每个对象。
我将示例从 Apollo dox 更改为涵盖您可能提供了不正确标识符的三种情况 - 它适用于您有不止一种 GraphQL 类型的情况:
dataIdFromObject: (obj) => {
let id = defaultDataIdFromObject(obj);
console.log('defaultDataIdFromObject OBJ ID', obj, id);
if (!id) {
const { __typename: typename } = obj;
switch (typename) {
case 'Blog': {
// if you are using other than 'id' and '_id' - 'blogId' in this case
const undef = `${typename}:${obj.id}`;
const defined = `${typename}:${obj.blogId}`;
console.log('in Blogs -', undef, defined);
return `${typename}:${obj.blogId}`; // return 'blogId' as it is a unique
//identifier. Using any other identifier will lead to above defined problem.
}
case 'Post': {
// if you are using hash key and sort key then hash key is not unique.
// If you do query in DB it will always be the same.
// If you do scan in DB quite often it will be the same value.
// So use both hash key and sort key instead to avoid the problem.
// Using both ensures ID used by Apollo is always unique.
// If for post you are using hashKey of blogID and sortKey of postId
const notUniq = `${typename}:${obj.blogId}`;
const notUniq2 = `${typename}:${obj.postId}`;
const uniq = `${typename}:${obj.blogId}${obj.postId}`;
console.log('in Post -', notUniq, notUniq2, uniq);
return `${typename}:${obj.blogId}${obj.postId}`;
}
case 'Comment': {
// lets assume 'comment's identifier is 'id'
// but you dont use it in your app and do not fetch from GraphQl, that is
// you omitted 'id' in your GraphQL query definition.
const undefnd = `${typename}:${obj.id}`;
console.log('in Comment -', undefnd);
// log result - null
// to fix it simply add 'id' in your GraphQL definition.
return `${typename}:${obj.id}`;
}
default: {
console.log('one falling to default-not good-define this in separate Case', ${typename});
return id;
}
我希望你现在看到其他两个答案中的方法是有风险的。
您始终拥有唯一的标识符。简单地帮助 APOLLO 知道它在对象中的哪个字段。如果它不是通过在查询定义中添加来获取的,请添加它。
我正在使用 react-apollo 开发一个 React 应用程序
当我检查浏览器网络选项卡响应时通过 graphql 调用数据它显示数组的所有元素不同
但是我在我的应用程序中得到或 console.log()
然后数组的所有元素与第一个元素相同。
我不知道如何解决请帮助
将此放入您的 App.js
cache: new InMemoryCache({
dataIdFromObject: o => o.id ? `${o.__typename}-${o.id}` : `${o.__typename}-${o.cursor}`,
})
发生这种情况的原因是数组中的项目 "normalized" 与 Apollo 缓存中的值相同。 AKA,它们在阿波罗看来是一样的。这通常是因为它们共享相同的 Symbol(id)
.
如果你打印出你的 Apollo 响应对象,你会注意到每个对象都有 Symbol(id)
,它被 Apollo 缓存使用。您的数组项可能具有相同的 Symbol(id)
,这会导致它们重复。为什么会这样?
默认情况下,Apollo 缓存运行此 function 进行规范化。
export function defaultDataIdFromObject(result: any): string | null {
if (result.__typename) {
if (result.id !== undefined) {
return `${result.__typename}:${result.id}`;
}
if (result._id !== undefined) {
return `${result.__typename}:${result._id}`;
}
}
return null;
}
您的数组项目属性导致多个项目 return 相同的数据 ID。在我的例子中,多个项目有 _id = null
导致所有这些项目被重复。当这个函数 return 为 null 时 docs 说
InMemoryCache will fall back to the path to the object in the query, such as ROOT_QUERY.allPeople.0 for the first record returned on the allPeople root query.
当我们的数组项不能很好地与 defaultDataIdFromObject
一起工作时,这是我们真正想要的行为。
因此,解决方案是使用传递给 ApolloClient
中的 InMemoryCache
构造函数的 dataIdFromObject
选项手动配置这些唯一标识符。以下对我有用,因为我所有的对象都使用 _id 并且有 __typename.
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache({
dataIdFromObject: o => (o._id ? `${o.__typename}:${o._id}`: null),
})
});
我认为应避免使用其他两个答案中的方法,而应采用以下方法:
其实很简单。要了解它是如何工作的,只需按如下方式记录 obj:
dataIdFromObject: (obj) => {
let id = defaultDataIdFromObject(obj);
console.log('defaultDataIdFromObject OBJ ID', obj, id);
}
如果遇到此问题,您会在日志中看到 id 将为空。
注意记录'obj'。将为返回的每个对象打印它。
这些对象是 Apollo 试图从中获取唯一 ID 的对象(您必须告诉 Apollo 对象中的哪个字段对于从 GraphQL 返回的 'items' 数组中的每个对象都是唯一的 - 相同当您使用 'map' 或渲染 DOM 元素时的其他迭代时,您在 React 中为 'key' 传递唯一值的方式。
By default, InMemoryCache will attempt to use the commonly found primary keys of id and _id for the unique identifier if they exist along with __typename on an object.
因此请查看 'defaultDataIdFromObject ' 使用的记录 'obj' - 如果您没有看到 'id' 或“_id”,那么您应该在您的对象中提供唯一的字段每个对象。
我将示例从 Apollo dox 更改为涵盖您可能提供了不正确标识符的三种情况 - 它适用于您有不止一种 GraphQL 类型的情况:
dataIdFromObject: (obj) => {
let id = defaultDataIdFromObject(obj);
console.log('defaultDataIdFromObject OBJ ID', obj, id);
if (!id) {
const { __typename: typename } = obj;
switch (typename) {
case 'Blog': {
// if you are using other than 'id' and '_id' - 'blogId' in this case
const undef = `${typename}:${obj.id}`;
const defined = `${typename}:${obj.blogId}`;
console.log('in Blogs -', undef, defined);
return `${typename}:${obj.blogId}`; // return 'blogId' as it is a unique
//identifier. Using any other identifier will lead to above defined problem.
}
case 'Post': {
// if you are using hash key and sort key then hash key is not unique.
// If you do query in DB it will always be the same.
// If you do scan in DB quite often it will be the same value.
// So use both hash key and sort key instead to avoid the problem.
// Using both ensures ID used by Apollo is always unique.
// If for post you are using hashKey of blogID and sortKey of postId
const notUniq = `${typename}:${obj.blogId}`;
const notUniq2 = `${typename}:${obj.postId}`;
const uniq = `${typename}:${obj.blogId}${obj.postId}`;
console.log('in Post -', notUniq, notUniq2, uniq);
return `${typename}:${obj.blogId}${obj.postId}`;
}
case 'Comment': {
// lets assume 'comment's identifier is 'id'
// but you dont use it in your app and do not fetch from GraphQl, that is
// you omitted 'id' in your GraphQL query definition.
const undefnd = `${typename}:${obj.id}`;
console.log('in Comment -', undefnd);
// log result - null
// to fix it simply add 'id' in your GraphQL definition.
return `${typename}:${obj.id}`;
}
default: {
console.log('one falling to default-not good-define this in separate Case', ${typename});
return id;
}
我希望你现在看到其他两个答案中的方法是有风险的。
您始终拥有唯一的标识符。简单地帮助 APOLLO 知道它在对象中的哪个字段。如果它不是通过在查询定义中添加来获取的,请添加它。