问题描述
我正在使用反应 - apollo的反应应用程序 通过GraphQL调用数据当我检查浏览器网络标签响应时,它显示了阵列的所有元素 但是我在我的应用程序中获得或console.log()然后与第一个元素相同的所有元素. 我不知道如何修复请帮助
推荐答案
将此放在您的App.js中
cache: new InMemoryCache({ dataIdFromObject: o => o.id ? `${o.__typename}-${o.id}` : `${o.__typename}-${o.cursor}`, })
其他推荐答案
这发生的原因是因为阵列中的项目在Apollo缓存中将"归一化"到相同的值.又名,他们看起来也一样.这通常发生,因为它们共享相同的Symbol(id).
如果打印出apollo响应对象,则会注意到每个对象都有Symbol(id),它由apollo缓存使用.您的数组项目可能具有相同的Symbol(id),导致它们重复.为什么会发生这种情况?
默认情况下,apollo缓存运行这个函数用于归一化.
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; }
您的数组项属性会导致多个项目返回相同的数据ID.在我的情况下,多个项目具有_id = null,导致所有这些项目重复.当此函数返回null时, docs 说
inmemorycache将返回到查询中对象的路径, 如root_query.allpeople.0为第一个记录返回 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在日志中会为null.
注意记录'obj'.它将打印返回的每个对象.
这些对象是apollo尝试获取唯一ID的对象(您必须告诉Apollo您对象中的哪些字段对从GraphQ返回的"项目"阵列中的每个对象都是唯一的 - 相同的方式当您在渲染DOM元素时使用"Map"或其他迭代时,在"键"中的"键"值).
默认情况下,InmemoryCache将尝试使用常用的找到 如果存在唯一标识符,则ID和_ID的主要键 以及对象上的__typename.
所以查看'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.如果未通过添加查询定义添加它,则添加它.
问题描述
I am working on a react app with react-apollo calling data through graphql when I check in browser network tab response it shows all elements of the array different but what I get or console.log() in my app then all elements of array same as the first element. I don't know how to fix please help
推荐答案
Put this in your App.js
cache: new InMemoryCache({ dataIdFromObject: o => o.id ? `${o.__typename}-${o.id}` : `${o.__typename}-${o.cursor}`, })
其他推荐答案
The reason this happens is because the items in your array get "normalized" to the same values in the Apollo cache. AKA, they look the same to Apollo. This usually happens because they share the same Symbol(id).
If you print out your Apollo response object, you'll notice that each of the objects have Symbol(id) which is used by Apollo cache. Your array items probably have the same Symbol(id) which causes them to repeat. Why does this happen?
By default, Apollo cache runs this function for normalization.
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; }
Your array item properties cause multiple items to return the same data id. In my case, multiple items had _id = null which caused all of these items to be repeated. When this function returns null the docs say
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.
This is the behavior we actually want when our array items don't work well with defaultDataIdFromObject.
Therefore the solution is to manually configure these unique identifiers with the dataIdFromObject option passed to the InMemoryCache constructor within your ApolloClient. The following worked for me as all my objects use _id and had __typename.
const client = new ApolloClient({ link: authLink.concat(httpLink), cache: new InMemoryCache({ dataIdFromObject: o => (o._id ? `${o.__typename}:${o._id}`: null), }) });
其他推荐答案
I believe the approach in other two answers should be avoided in favor of following approach:
Actually it is quite simple. To understand how it works simply log obj as follows:
dataIdFromObject: (obj) => { let id = defaultDataIdFromObject(obj); console.log('defaultDataIdFromObject OBJ ID', obj, id); }
You will see that id will be null in your logs if you have this problem.
Pay attention to logged 'obj'. It will be printed for every object returned.
These objects are the ones from which Apollo tries to get unique id ( you have to tell to Apollo which field in your object is unique for each object in your array of 'items' returned from GraphQL - the same way you pass unique value for 'key' in React when you use 'map' or other iterations when rendering DOM elements).
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.
So look at logged 'obj' used by 'defaultDataIdFromObject ' - if you don't see 'id' or '_id' then you should provide the field in your object that is unique for each object.
I changed example from Apollo dox to cover three cases when you may have provided incorrect identifiers - it is for cases when you have more than one GraphQL types:
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; }
I hope now you see that the approach in other two answers are risky.
YOU ALWAYS HAVE UNIQUE IDENTIFIER. SIMPLY HELP APOLLO BY LETTING KNOW WHICH FIELD IN OBJECT IT IS. If it is not fetched by adding in query definition add it.