在Apollo Client 3中合并非规范化数据时,会出现“缓存数据可能丢失”警告

问题描述

我正在使用Apollo Client将应用程序从v2升级到v3,但找不到以下问题的正确解决方案。

我有一个包含产品的架构,在该产品中包含一个价格。这个价格不是一个简单的数字,因为它包含免税价值,所有税项包括价值和增值税。

type Product {
   id: ID
   price: Price
}

type Price {
   dutyFree: Float
   allTaxesIncluded: Float
   VAT: Float
}

在Apollo Client 2中,每当没有显式id或_id属性时,InMemoryCache都会根据对象的路径创建后备假标识符来规范化数据。

在Apollo Client 3中,不再生成此后备假标识符。相反,您有两个选择来处理非规范化数据。第一种是使用新的TypePolicy选项,并明确指示您接收的数据不应进行规范化。在这种情况下,数据将链接到父标准化数据。

文档:

未规范化的对象将嵌入到缓存的父对象中。您不能直接访问这些对象,但可以通过其父对象访问它们。

new InMemoryCache({
   typePolicies: {
      Price {
         keyFields: false
      }
   }
})

很高兴,尽管我的问题解决了,但我还是很高兴。好吧,错了。。。我可以在我的应用中创建产品并添加价格。但是,只要更改现有价格,就会收到以下警告:

替换Product对象的price字段时,缓存数据可能会丢失。

因为,当我在更新后获得我的产品时,InMemoryCache不知道如何合并“价格”字段,因为没有定义id,这是非规范化数据的关键所在。

我知道有第二个选项可以为我的Product.price字段显式定义合并函数,但是此示例是实际的简单版本。我有大量通过多个对象键入多个对象的字段,这些对象的类型为Price,而为每个对象手动定义一个合并函数(即使是通过外部化函数中的通用逻辑)也是我发现效率低下和产生错误的原因。

所以我的问题是:我对keyFields: false选项有什么误解,我该怎么做才能解决此问题,而不必诉诸于在我的应用程序中为50多个字段定义合并功能

感谢您的帮助:)

解决方法

我不确定您是否误解了 keyFields: false。我的理解是,当 Product 在缓存中更新时,InMemoryCache 必须处理嵌入在旧 {{1} 的 Price 字段中的 price 对象中的任何差异} 和新的 Product。如果没有 Product 来定义应该如何完成,缓存会记录警告。

从 Apollo Client 3.3 开始,TypePolicy 函数可以是 defined for types in addition to fields。这是他们文档中的一个示例:

merge

由于您不想逐个字段地定义合并函数,您可以尝试为 const cache = new InMemoryCache({ typePolicies: { Book: { fields: { // No longer necessary! // author: { // merge: true,// },},Author: { merge: true,}); 类型定义合并函数。