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

How to separate logic when updating Apollo cache that used as global store?

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

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

我不知道如何用 Apollo 实现它。医生说

When mutation modifies multiple entities, or if it creates or deletes entities, the Apollo Client cache is not automatically updated to reflect the result of the mutation. To resolve this, your call to useMutation can include an update function.

在处理所有缓存更新的应用程序的一部分中添加一个 update 函数;通过 更新应用程序所有其他部分的查询 and/or 片段,正是我们想要在 Flux / 事件驱动架构中避免的。

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

1.收件箱数量 显示 SideNav

中收件箱项目数的组件
query getInboxCount {
    inbox {
        id
        count
    }
}

2。收件箱列表项 在收件箱页面中显示项目的组件

query getInbox {
    inbox {
        id
        items {
            ...ItemPreview
            ...ItemDetail
        }
    }
}

这两个组件从那些来自自动生成的挂钩的 GQL 查询中读取 数据,即。 const { data, loading } = useGetInboxItemsQuery()

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

(伪代码)

    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)
            }
        },
    })

在这里,我的 AddItem 组件必须 知道 我在我的应用程序中声明的不同的其他查询/片段此外,由于它非常冗长,复杂性增加得非常快在 update 方法中。特别是当多个列表/查询应该更新时 here

有没有人有关于实施更多独立组件的建议?我创建查询的方式有误吗?

关于 update 的不幸事实是它以简单性换取性能。一个真正的 "dumb" 客户端只会从服务器接收数据并呈现它,而不会对其进行操作。通过指示 Apollo 在突变后如何修改我们的缓存,我们不可避免地复制了我们服务器上已经存在的业务逻辑。避免这种情况的唯一方法是:

  • 使突变 return 成为图表的较大部分。例如,如果用户创建了一个 post,而不是 return 创建的 post,return 完整的用户对象,包括用户的所有 post s.
  • 重新获取受影响的查询。

当然,通常这两种方法都不是特别理想,我们选择将业务逻辑注入到我们的客户端应用程序中。

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