"Cache data may be lost" warning when merging non-normalized data in Apollo Client 3
Asked Answered
L

1

7

I'm upgrading my application with Apollo Client from v2 to v3 and I can't find the correct solution to the following problem.

I have a schema with a product and inside this product, a price. This price is not a simple number as it contains the duty free value, the all taxes included value and the VAT.

type Product {
   id: ID
   price: Price
}

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

In Apollo Client 2, whenever there was no explicit id or _id property, the InMemoryCache created a fallback fake identifier to normalize data, based on the path to the object.

In Apollo Client 3, this fallback fake identifier is no longer generated. Instead you have two options to handle non-normalized data. The first is to use the new TypePolicy option and indicates explicitly the data you receive should not be normalize. In that case, data will be linked to the parent normalized data.

The doc :

Objects that are not normalized are instead embedded within their parent object in the cache. You can't access these objects directly, but you can access them via their parent.

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

All happy, I though my problem was solved. Well, wrong ... I can create a product in my app and add a price. But whenever I change an existing price, I get the following warning :

Cache data may be lost when replacing the price field of a Product object.

Because, when I get my Product after an update, the InMemoryCache does not know how to merge the field Price because no id is defined, which is the point of non-normalized data.

I know there is the second option to explicitly define a merge function for my Product.price field, but this example is a simpler version of the reality. I have a large number of fields through multiple objects which are typed Price, and manually defining a merge function for each and everyone one of them (even by externalizing the common logic in a function) is something I find quite inefficient and source of errors.

So my question is : what did I misunderstood about the keyFields: false option and what can I do to solve this problem without having to resort to define a merge function to 50+ fields in my app ?

Thanks for the help :)

Loaiasis answered 25/8, 2020 at 17:50 Comment(0)
B
0

I'm not sure you've misunderstood keyFields: false. My understanding is that when the Product is updated in the cache, InMemoryCache must handle any differences in the Price objects embedded in the price field of the old Product and the new Product. If there isn't a TypePolicy to define how that should be done, the cache logs a warning.

Starting in Apollo Client 3.3, merge functions can be defined for types in addition to fields. Here's an example from their docs:

const cache = new InMemoryCache({
  typePolicies: {
    Book: {
      fields: {
        // No longer necessary!
        // author: {
        //   merge: true,
        // },
      },
    },

    Author: {
      merge: true,
    },
  },
});

Since you don't want to define a merge function on a field-by-field basis, you might try defining the merge function for the Price type instead.

Brout answered 15/5, 2021 at 8:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.