Search code examples
javascriptreactjsgraphqlapolloapollo-client

Defining custom merge function to resolve InMemoryCache merge in GraphQL


I'm getting a warning:

Cache data may be lost when replacing the parts field of a Query object.

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

  existing: [{"__ref":"Part:53"},{"__ref":"Part:55"},{"__ref":"Part:56"},{"__ref":"Part:57"},{"__ref":"Part:58"}]
  incoming: [{"__ref":"Part:53"},{"__ref":"Part:55"},{"__ref":"Part:56"},{"__ref":"Part:57"}]

Now here is my Part type:

type Part {
  id: ID!
  created_at: DateTime!
  updated_at: DateTime!
  partName: String
  partDescription: String
  partQuantity: Long
  usePercentage: Boolean
  partPercentage: Float
  type: String
  published_at: DateTime
  products(sort: String, limit: Int, start: Int, where: JSON): [Product]
  partImage(sort: String, limit: Int, start: Int, where: JSON): [UploadFile]
  stockevents(sort: String, limit: Int, start: Int, where: JSON): [Stockevent]
}

This warning triggers after I remove one part using mutation to delete a single part. Here it is:

const [partDelete] = useMutation(DELETE_PART, {
        update(cache, { data }) {
            const newData = Object.values(data)
            const refresh = newData.map(name => name.part)
            const refined = refresh.map(item => item.id)
            cache.evict({
                id: cache.identify({
                    id: refined.id
                })
            })
            cache.writeQuery({
                query: GET_PARTS
            })
        },
        refetchQueries: [
          { query: GET_PARTS }
        ]
    })

I am passing payload in a separate function and everything works but I keep getting this cache warning so I want to deal with it now.

I've went with updating InMemoryCache in my index.js but it still doesn't work:

export const client = new ApolloClient({
  link,
  cache: new InMemoryCache({
    typePolicies: {
      Part: {
          merge(existing = [], incoming = []) {
            return [...existing, ...incoming];
          }
      }
    }
  })
});

I've also tried to return only ...incoming but nothing different happens.

Thanks in advance, cheers!


Solution

  • The issue was in the structure of InMemoryCache config. After I changed it to this it worked:

    export const client = new ApolloClient({
      link,
      cache: new InMemoryCache({
        typePolicies: {
          Query: {
            Part: {
              parts: {
                fields: {
                  merge(existing, incoming) {
                    return incoming;
                  }
                }
              }
            }
          }
        }
      })
    });
    

    I have also removed update option from the mutation that includes evict and modify.