删除带有突变的项目时如何正确修改Apollo缓存

Posted

技术标签:

【中文标题】删除带有突变的项目时如何正确修改Apollo缓存【英文标题】:How to properly modify Apollo cache when removing item with mutation 【发布时间】:2020-12-14 14:01:42 【问题描述】:

我不确定自己做错了什么,因为一切正常,但每次运行DELETE_PHOTOmutation 时都会收到这个讨厌的错误消息:

替换用户的照片字段时缓存数据可能会丢失 对象。

我有用户对象,其中包含照片列表:

email: "test@test.fi"
fullname: "Test user"
id: "5f058ca0bf08318028019059"
isAdmin: true
photos:
    0:"__ref":"Photo:5f44b37892f7b011ec491f25"
    1:"__ref":"Photo:5f44b37a92f7b011ec491f26"
    2:"__ref":"Photo:5f44b37d92f7b011ec491f27"
    3:"__ref":"Photo:5f44b38192f7b011ec491f28"
    4:"__ref":"Photo:5f44b38792f7b011ec491f2a"
    5:"__ref":"Photo:5f44b38992f7b011ec491f2b"
    6:"__ref":"Photo:5f44b38c92f7b011ec491f2c"
    7:"__ref":"Photo:5f44b38e92f7b011ec491f2d"
    8:"__ref":"Photo:5f44b39092f7b011ec491f2e"
    9:"__ref":"Photo:5f44b39292f7b011ec491f2f"
    10:"__ref":"Photo:5f44b39492f7b011ec491f30"
    11:"__ref":"Photo:5f44b39892f7b011ec491f31"
    12:"__ref":"Photo:5f44b39a92f7b011ec491f32"
    13:"__ref":"Photo:5f44b39d92f7b011ec491f33"
    14:"__ref":"Photo:5f44b3a092f7b011ec491f34"
    15:"__ref":"Photo:5f44b3a492f7b011ec491f35"
    16:"__ref":"Photo:5f44b3a792f7b011ec491f36"
    17:"__ref":"Photo:5f44b3aa92f7b011ec491f37"
    18:"__ref":"Photo:5f44b3ad92f7b011ec491f38"
    19:"__ref":"Photo:5f44b3af92f7b011ec491f39"
    20:"__ref":"Photo:5f44b3b292f7b011ec491f3a"
    21:"__ref":"Photo:5f44b3b592f7b011ec491f3b"
    22:"__ref":"Photo:5f44c5e192f7b011ec491f3c"
    23:"__ref":"Photo:5f453f1e479a7649e8191a04"
username: "admin"

每个照片对象都是这样的:

dateAdded: "1598337912783"
description: null
filename: "images/851ca650-e69e-11ea-bdf1-eb9595fbd23e"
id: "5f44b37892f7b011ec491f25"
mainUrl: "https://firebasestorage.googleapis.com/..."
name: "2013-07-27 12-25-40 1479 (Canon EOS 40D)"
originalFilename: "2013-07-27 12-25-40 1479 (Canon EOS 40D).jpg"
thumbFilename: "images/851ca651-e69e-11ea-bdf1-eb9595fbd23e"
thumbUrl: "https://firebasestorage.googleapis.com/..."

获取用户对象的查询是:

export const ME = gql`
  query me 
    me 
      username,
      email,
      fullname,
      isAdmin,
      photos 
        mainUrl,
        thumbUrl,
        filename,
        thumbFilename,
        originalFilename,
        name,
        description,
        dateAdded,
        id
      ,
      id
    
  
`;

而删除照片的突变是:

export const DELETE_PHOTO = gql`
  mutation deletePhoto(
    $id: ID!
  ) 
      deletePhoto(
        id: $id
      ) 
        mainUrl,
        thumbUrl,
        filename,
        thumbFilename,
        originalFilename,
        name,
        description,
        dateAdded,
        id
      
    
`;

当我执行DELETE_PHOTO 查询时,我得到这个关于已删除照片的对象作为响应:

deletePhoto:
    dateAdded: "1598337912783"
    description: null
    filename: "images/851ca650-e69e-11ea-bdf1-eb9595fbd23e"
    id: "5f44b37892f7b011ec491f25"
    mainUrl: "https://firebasestorage.googleapis.com/..."
    name: "2013-07-27 12-25-40 1479 (Canon EOS 40D)"
    originalFilename: "2013-07-27 12-25-40 1479 (Canon EOS 40D).jpg"
    thumbFilename: "images/851ca651-e69e-11ea-bdf1-eb9595fbd23e"
    thumbUrl: "https://firebasestorage.googleapis.com/..."
    __typename: "Photo"

然后我使用以下代码通过从用户对象的照片数组中删除该项目来更新 Apollo 缓存:

const [deletePhotoFromDb] = useMutation(DELETE_PHOTO, 
  update: (cache, response) => 
    const existingCache = cache.readQuery( query: ME );
    if (existingCache) 
      const idToDelete = response.data.deletePhoto.id;
      const updatedPhotos = existingCache.me.photos.filter(p => p.id !== idToDelete);

      const updatedCache = 
        ...existingCache,
        me: 
          ...existingCache.me,
          photos: updatedPhotos
        
      ;

      cache.writeQuery(
        query: ME,
        data: updatedCache
      );
    
  
);

更新缓存有效,因为照片会立即从 React 的 UI 中删除。如果不更新缓存,照片将不会从 UI 中删除。

那么,我做错了什么来获取有关丢失缓存的错误消息?

Cache data may be lost when replacing the photos field of a User object.

To address this problem (which is not a bug in Apollo Client), define a custom merge function for the User.photos field, so InMemoryCache can safely merge these objects:

  existing: ["__ref":"Photo:5f44b37a92f7b011ec491f26","__ref":"Photo:5f44b37d92f7b011ec491f27","__ref":"Photo:5f44b38192f7b011ec491f28","__ref":"Photo:5f44b38792f7b011ec491f2a","__ref":"Photo:5f44b38992f7b011ec491f2b","__ref":"Photo:5f44b38c92f7b011ec491f2c","__ref":"Photo:5f44b38e92f7b011ec491f2d","__ref":"Photo:5f44b39092f7b011ec491f2e","__ref":"Photo:5f44b39292f7b011ec491f2f","__ref":"Photo:5f44b39492f7b011ec491f30","__ref":"Photo:5f44b39892f7b011ec491f31","__ref":"Photo:5f44b39a92f7b011ec491f32","__ref":"Photo:5f44b39d92f7b011ec491f33","__ref":"Photo:5f44b3a092f7b011ec491f34","__ref":"Photo:5f44b3a492f7b011ec491f35","__ref":"Photo:5f44b3a792f7b011ec491f36","__ref":"Photo:5f44b3aa92f7b011ec491f37","__ref":"Photo:5f44b3ad92f7b011ec491f38","__ref":"Photo:5f44b3af92f7b011ec491f39","__ref":"Photo:5f44b3b292f7b011ec491f3a","__ref":"Photo:5f44b3b592f7b011ec491f3b","__ref":"Photo:5f44c5e192f7b011ec491f3c","__ref":"Photo:5f453f1e479a7649e8191a04"]
  incoming: ["__ref":"Photo:5f44b37a92f7b011ec491f26","__ref":"Photo:5f44b37d92f7b011ec491f27","__ref":"Photo:5f44b38192f7b011ec491f28","__ref":"Photo:5f44b38792f7b011ec491f2a","__ref":"Photo:5f44b38992f7b011ec491f2b","__ref":"Photo:5f44b38c92f7b011ec491f2c","__ref":"Photo:5f44b38e92f7b011ec491f2d","__ref":"Photo:5f44b39092f7b011ec491f2e","__ref":"Photo:5f44b39292f7b011ec491f2f","__ref":"Photo:5f44b39492f7b011ec491f30","__ref":"Photo:5f44b39892f7b011ec491f31","__ref":"Photo:5f44b39a92f7b011ec491f32","__ref":"Photo:5f44b39d92f7b011ec491f33","__ref":"Photo:5f44b3a092f7b011ec491f34","__ref":"Photo:5f44b3a492f7b011ec491f35","__ref":"Photo:5f44b3a792f7b011ec491f36","__ref":"Photo:5f44b3aa92f7b011ec491f37","__ref":"Photo:5f44b3ad92f7b011ec491f38","__ref":"Photo:5f44b3af92f7b011ec491f39","__ref":"Photo:5f44b3b292f7b011ec491f3a","__ref":"Photo:5f44b3b592f7b011ec491f3b","__ref":"Photo:5f44c5e192f7b011ec491f3c"]

【问题讨论】:

apollographql.com/docs/react/caching/cache-field-behavior/… ? ...替换...不存在,只有传入? 感谢 xadm!那行得通:) 【参考方案1】:

感谢 xadm 为我指明了 cmets 的正确方向。

我用以下内容替换了空的 InMemoryCache 对象,并且不再有警告消息:

const cache = new InMemoryCache(
  typePolicies: 
    User: 
      fields: 
        photos: 
          merge(existing = [], incoming: any[]) 
            return [...incoming];
          
        
      
    
  
);

【讨论】:

以上是关于删除带有突变的项目时如何正确修改Apollo缓存的主要内容,如果未能解决你的问题,请参考以下文章

在 Apollo 中删除突变后如何重定向?

如何在 Apollo / GraphQL 发生突变后更新缓存?

Apollo / GraphQl - 单实体突变不更新缓存(数据库更新)

如何从突变查询中更新 Apollo 数据存储/缓存,更新选项似乎没有触发

如何在突变后更新阿波罗缓存(使用过滤器查询)

创建突变后添加到 Apollo 客户端缓存中的数组