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

问题描述

我不确定自己在做什么错,因为一切正常,但是每次运行DELETE_PHOTO突变时,我都会收到此讨厌的错误消息:

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

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

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,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:5f44c5e192f7b011ec491f3c"}]

解决方法

感谢 xadm 将我指向正确的评论方向。

我将空的InMemoryCache对象替换为以下内容,并且不再显示警告消息:

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