Apollo client v3 "Cache data may be lost when replacing the field X of a Y object"

3.9k Views Asked by At

I have two simple queries:

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

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

But in the console I see a warning:

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

Is there a way just do not merge them and remove the warning? Because if specify in typePolicies

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

it is not what I want, because these are different data and these two queues do not need to be merged in any way. Also, I don't have an id field and keyFields will not work for this case, because labels could be the same for both menus

1

There are 1 best solutions below

0
On BEST ANSWER

So your question is hard to answer without your schema typedefs. But let's suppose it's something like this:

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

The warning is essentially saying that without any keyArgs Apollo Cache has no way to normalize the menus Query. Keep in mind from their standpoint- you have a single menus root query. (i.e. GerMenuA and GerMenuB are client side queries not root queries).

(Side note- since you don't have id fields see disabling normalization.)

Option 1: Separate Your Queries

type Query {
  menuA: Menu
  menuB: Menu
}

Apollo cache will now store menuA and menuB as separate queries. If you want to be safe you can set your type policies:

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

keyFields: false tells AC to store Menu under it's parent query. keyArgs: false says that both menuA and menuB are singleton queries. Cache policy will default to merge: false so that existing data will be replaced by incoming.

Option 2: Define Query Parameter

In this option, you add a name parameter to your menus query:

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

By default, the cache stores a separate value for every unique combination of argument values you provide when querying a particular field.

Apollo cache will now store menus:{name:menuA} and menus:{name:menuB} as separate cache objects. Again, if you want to be safe you can set your type policies:

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

Again, the cache policy will default to merge: false so that existing data will be replaced by incoming.

Option 3: Define Merge Policy

We've covered why the existing schema is confusing to Apollo Cache. But if you're really set on it, the remaining thing to do is define a merge policy:

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

merge: true tells Apollo Cache to merge the results of GerMenuA and GerMenuB into a single Menus cache object with both menuA and menuB properties. Without it each time you ran a query you'd blow away the results of the previous query.