Graphql 更新用作全局存储的Apollo缓存时,如何分离逻辑?

Graphql 更新用作全局存储的Apollo缓存时,如何分离逻辑?,graphql,react-apollo,apollo-client,flux,Graphql,React Apollo,Apollo Client,Flux,使用Apollo缓存作为全局存储—用于远程和本地数据,非常方便 然而,虽然我从未使用过redux,但我认为它最重要的是实现flux:前端的事件驱动架构可以分离逻辑并确保关注点的分离 我不知道如何用阿波罗实现这一点。医生说 当变异修改多个实体时,或者如果它创建或删除实体,Apollo客户端缓存不会自动更新以反映变异的结果。要解决这个问题,对UseMotation的调用可以包括一个更新函数 在处理所有缓存更新的应用程序的一个部分中添加一个update函数;通过更新应用程序所有其他部分的查询和/或片段

使用Apollo缓存作为全局存储—用于远程和本地数据,非常方便

然而,虽然我从未使用过redux,但我认为它最重要的是实现flux:前端的事件驱动架构可以分离逻辑并确保关注点的分离

我不知道如何用阿波罗实现这一点。医生说

当变异修改多个实体时,或者如果它创建或删除实体,Apollo客户端缓存不会自动更新以反映变异的结果。要解决这个问题,对UseMotation的调用可以包括一个更新函数

在处理所有缓存更新的应用程序的一个部分中添加一个
update
函数;通过更新应用程序所有其他部分的查询和/或片段,这正是我们希望在Flux事件驱动体系结构中避免的

为了说明这一点,让我举一个简单的例子。这里,我们有(至少3个链接组件)

1。收件箱计数 显示
SideNav中收件箱项目数的组件

query getInboxCount {
    inbox {
        id
        count
    }
}
2。收件箱列表项目 在收件箱页面中显示项目的组件

query getInbox {
    inbox {
        id
        items {
            ...ItemPreview
            ...ItemDetail
        }
    }
}
这两个组件都从自动生成的钩子读取GQL查询中的数据,即.
const{data,load}=useGetInboxItemsQuery()

3。附加项 创建新项的组件。因为它创建了一个新的实体,我需要手动更新缓存。所以我不得不写

(伪代码)

const[addItem,{loading}]=useCreateItem({
更新(缓存,{data}){
const cachedData=cache.readQuery({
查询:GetInboxItemsDocument,
})
如果(缓存数据?.inbox){
//1.更新项目列表GetInboxItemsQuery
const newItems=cachedData.inbox.items.concat(data.items)
cache.writeQuery({
查询:GetInboxItemsDocument,
数据:{
收件箱:{
id:'我',
__typename:“收件箱”,
项目:新项目,
},
},
})
//2.更新另一个封装到另一个可重用方法中的查询,如下所示
setInboxCount(缓存,newItems.length)
}
},
})

在这里,我的
AddItem
组件必须知道我在应用程序中声明的不同的其他查询/片段关于
update
的不幸事实是,它以简单性换取性能。真正的“哑”客户机只会从服务器接收数据并进行渲染,而不会对其进行操作。通过指示Apollo在发生变异后如何修改缓存,我们不可避免地复制了服务器上已经存在的业务逻辑。避免这种情况的唯一方法是:

  • 让变异返回图的较大部分。例如,如果用户创建帖子,则返回完整的用户对象,包括用户的所有帖子,而不是返回创建的帖子
  • 重新提取受影响的查询
当然,通常这两种方法都不是特别可取的,我们选择将业务逻辑注入到客户端应用程序中


分离此业务逻辑可能非常简单,只需将更新函数保存在一个单独的文件中,然后根据需要导入它们即可。这样,至少可以单独测试更新逻辑。您也可能更喜欢更优雅的解决方案,如利用链接。是一个很好的链接示例,它允许您将
update
逻辑与组件分离。它还解决了必须跟踪查询变量才能执行这些更新的问题。

实际上,您应该对两个位置使用
count
属性(如果不需要重新查询,则需要一个写缓存)-收件箱(所有空间/位置)应该分页,并使用“显示更多”或使用虚拟化列表呈现
    const [addItem, { loading }] = useCreateItemMutation({
        update(cache, { data }) {
            const cachedData = cache.readQuery<GetInboxItemsQuery>({
                query: GetInboxItemsDocument,
            })

            if (cachedData?.inbox) {

                // 1. Update items list GetInboxItemsQuery
                const newItems = cachedData.inbox.items.concat(data.items)
                cache.writeQuery({
                    query: GetInboxItemsDocument,
                    data: {
                        inbox: {
                            id: 'me',
                            __typename: 'Inbox',
                            items: newItems,
                        },
                    },
                })

               // 2. Update another query wrapped into another reusable method, here
                setInboxCount(cache, newItems.length)
            }
        },
    })