【问题标题】:Apollo client v3 "Cache data may be lost when replacing the field X of a Y object"Apollo 客户端 v3“替换 Y 对象的字段 X 时可能会丢失缓存数据”
【发布时间】:2021-05-25 21:54:20
【问题描述】:

我有两个简单的查询:

query GerMenuA {
  menus {
    menuA {
      items {
        label
      }
    }
  }
}

query GerMenuB {
  menus {
    menuB {
      items {
        label
      }
    }
  }
}

但在控制台中我看到一个警告:

Cache data may be lost when replacing the menus field of a Query object.
existing: {"__typename":"Menu","menuA":[{...}]}
incoming: {"__typename":"Menu","menuB":[{...}]}

有没有办法不合并它们并删除警告?因为如果在typePolicies中指定@

Menu: { merge: true }
or
Menu: { merge: false }

这不是我想要的,因为这些是不同的数据,这两个队列不需要以任何方式合并。另外,我没有id 字段,keyFields 不适用于这种情况,因为两个菜单的标签可能相同

【问题讨论】:

    标签: reactjs apollo-client react-apollo apollo-cache-inmemory


    【解决方案1】:

    因此,如果没有您的架构类型定义,您的问题很难回答。但是让我们假设它是这样的:

    type Query {
      menus: Menus
    }
    type Menus {
      menuA: Menu
      menuB: Menu
    }
    

    警告本质上是说没有任何keyArgs Apollo Cache 无法规范化menus 查询。从他们的角度记住 - 你有一个 single menus root 查询。 (即GerMenuAGerMenuB 是客户端查询而不是root 查询)。

    (旁注 - 因为您没有 id 字段,请参阅 disabling normalization。)

    选项 1:分离您的查询

    type Query {
      menuA: Menu
      menuB: Menu
    }
    

    Apollo 缓存现在将 menuAmenuB 存储为单独的查询。如果您想安全起见,可以设置类型策略:

    const createCache = () => new InMemoryCache({
      typePolicies: {
        Menu: {
          keyFields: false
        },
        Query: {
          fields: {
            menuA: {
              keyArgs: false
            },
            menuB: {
              keyArgs: false
            }
          }
        }
      },
    });
    

    keyFields: false 告诉 AC 将 Menu 存储在它的父查询下。 keyArgs: false 表示 menuAmenuB 都是单例查询。缓存策略将默认为merge: false,以便现有数据将被传入的数据替换。

    选项 2:定义查询参数

    在此选项中,您将 name 参数添加到您的 menus 查询中:

    type Query {
      menus(name: String): Menu
    }
    

    默认情况下,缓存会为您在查询特定字段时提供的每个唯一参数值组合存储一个单独的值。

    Apollo 缓存现在将 menus:{name:menuA}menus:{name:menuB} 存储为单独的缓存对象。同样,如果您想安全起见,可以设置类型策略:

    const createCache = () => new InMemoryCache({
      typePolicies: {
        Menu: {
          keyFields: false
        }
      },
    });
    

    同样,缓存策略将默认为merge: false,以便现有数据将被传入的数据替换。

    选项 3:定义合并策略

    我们已经讨论了为什么现有架构会令 Apollo Cache 感到困惑。但如果你真的准备好了,剩下要做的就是定义一个合并策略:

    const createCache = () => new InMemoryCache({
      typePolicies: {
        Menu: {
          keyFields: false
        },
        Menus: {
          keyFields: false,
          merge: true
        },
        Query: {
          fields: {
            menus: {
              keyArgs: false,
              merge: true
            }
          }
        }
      },
    });
    

    merge: true 告诉 Apollo Cache 将 GerMenuAGerMenuB 的结果合并到具有 menuAmenuB 属性的单个 Menus 缓存对象中。每次运行查询时如果没有它,您会破坏前一个查询的结果。

    【讨论】:

      猜你喜欢
      • 2020-12-04
      • 1970-01-01
      • 2021-04-25
      • 2019-07-12
      • 2017-03-18
      • 2021-02-01
      • 2019-07-29
      • 2018-12-15
      • 2019-03-24
      相关资源
      最近更新 更多