Apollo GraphQL updateQuery 到 typePolicy
Apollo GraphQL updateQuery to typePolicy
我在用头撞墙。我已经更新到 Apollo 3,但不知道如何将 updateQuery
迁移到 typePolicy
。我正在做基本的基于延续的分页,这就是我过去合并 fetchMore
:
结果的方式
await fetchMore({
query: MessagesByThreadIDQuery,
variables: {
threadId: threadId,
limit: Configuration.MessagePageSize,
continuation: token
},
updateQuery: (prev, curr) => {
// Extract our updated message page.
const last = prev.messagesByThreadId.messages ?? []
const next = curr.fetchMoreResult?.messagesByThreadId.messages ?? []
return {
messagesByThreadId: {
__typename: 'MessagesContinuation',
messages: [...last, ...next],
continuation: curr.fetchMoreResult?.messagesByThreadId.continuation
}
}
}
我已经尝试自己编写 merge
typePolicy
,但它只是不断加载并抛出有关 Apollo 缓存中重复标识符的错误。这是我的 typePolicy
查询的样子。
typePolicies: {
Query: {
fields: {
messagesByThreadId: {
keyArgs: false,
merge: (existing, incoming, args): IMessagesContinuation => {
const typedExisting: IMessagesContinuation | undefined = existing
const typedIncoming: IMessagesContinuation | undefined = incoming
const existingMessages = (typedExisting?.messages ?? [])
const incomingMessages = (typedIncoming?.messages ?? [])
const result = existing ? {
__typename: 'MessageContinuation',
messages: [...existingMessages, ...incomingMessages],
continuation: typedIncoming?.continuation
} : incoming
return result
}
}
}
}
}
所以我能够解决我的 use-case。这似乎比实际需要的要难得多。我基本上必须尝试找到与传入匹配的现有项目并覆盖它们,以及添加缓存中尚不存在的任何新项目。
我还必须仅在提供延续令牌时应用此逻辑,因为如果它为 null 或未定义,我应该只使用传入值,因为这表明我们正在进行初始加载。
我的文档是这样的:
{
"items": [{ id: string, ...others }],
"continuation": "some_token_value"
}
我创建了一个通用类型策略,我可以将其用于我所有具有相似形状的文档。它允许我指定项目的名称 属性,我想缓存的关键参数是什么,以及 graphql 类型的名称。
export function ContinuationPolicy(keyArgs: Array<string>, itemPropertyKey: string, typeName: string) {
return {
keyArgs,
merge(existing: any, incoming: any, args: any) {
if (!!existing && !!args.args?.continuation) {
const existingItems = (existing ? existing[itemPropertyKey] : [])
const incomingItems = (incoming ? incoming[itemPropertyKey] : [])
let items: Array<any> = [...existingItems]
for (let i = 0; i < incomingItems.length; i++) {
const current = incomingItems[i] as any
const found = items.findIndex(m => m.__ref === current.__ref)
if (found > -1) {
items[found] === current
} else {
items = [...items, current]
}
}
// This new data is a continuation of the last data.
return {
__typename: typeName,
[itemPropertyKey]: items,
continuation: incoming.continuation
}
} else {
// When we have no existing data in the cache, we'll just use the incoming data.
return incoming
}
}
}
}
我在用头撞墙。我已经更新到 Apollo 3,但不知道如何将 updateQuery
迁移到 typePolicy
。我正在做基本的基于延续的分页,这就是我过去合并 fetchMore
:
await fetchMore({
query: MessagesByThreadIDQuery,
variables: {
threadId: threadId,
limit: Configuration.MessagePageSize,
continuation: token
},
updateQuery: (prev, curr) => {
// Extract our updated message page.
const last = prev.messagesByThreadId.messages ?? []
const next = curr.fetchMoreResult?.messagesByThreadId.messages ?? []
return {
messagesByThreadId: {
__typename: 'MessagesContinuation',
messages: [...last, ...next],
continuation: curr.fetchMoreResult?.messagesByThreadId.continuation
}
}
}
我已经尝试自己编写 merge
typePolicy
,但它只是不断加载并抛出有关 Apollo 缓存中重复标识符的错误。这是我的 typePolicy
查询的样子。
typePolicies: {
Query: {
fields: {
messagesByThreadId: {
keyArgs: false,
merge: (existing, incoming, args): IMessagesContinuation => {
const typedExisting: IMessagesContinuation | undefined = existing
const typedIncoming: IMessagesContinuation | undefined = incoming
const existingMessages = (typedExisting?.messages ?? [])
const incomingMessages = (typedIncoming?.messages ?? [])
const result = existing ? {
__typename: 'MessageContinuation',
messages: [...existingMessages, ...incomingMessages],
continuation: typedIncoming?.continuation
} : incoming
return result
}
}
}
}
}
所以我能够解决我的 use-case。这似乎比实际需要的要难得多。我基本上必须尝试找到与传入匹配的现有项目并覆盖它们,以及添加缓存中尚不存在的任何新项目。
我还必须仅在提供延续令牌时应用此逻辑,因为如果它为 null 或未定义,我应该只使用传入值,因为这表明我们正在进行初始加载。
我的文档是这样的:
{
"items": [{ id: string, ...others }],
"continuation": "some_token_value"
}
我创建了一个通用类型策略,我可以将其用于我所有具有相似形状的文档。它允许我指定项目的名称 属性,我想缓存的关键参数是什么,以及 graphql 类型的名称。
export function ContinuationPolicy(keyArgs: Array<string>, itemPropertyKey: string, typeName: string) {
return {
keyArgs,
merge(existing: any, incoming: any, args: any) {
if (!!existing && !!args.args?.continuation) {
const existingItems = (existing ? existing[itemPropertyKey] : [])
const incomingItems = (incoming ? incoming[itemPropertyKey] : [])
let items: Array<any> = [...existingItems]
for (let i = 0; i < incomingItems.length; i++) {
const current = incomingItems[i] as any
const found = items.findIndex(m => m.__ref === current.__ref)
if (found > -1) {
items[found] === current
} else {
items = [...items, current]
}
}
// This new data is a continuation of the last data.
return {
__typename: typeName,
[itemPropertyKey]: items,
continuation: incoming.continuation
}
} else {
// When we have no existing data in the cache, we'll just use the incoming data.
return incoming
}
}
}
}