Apollo Client replaces an array of objects with the same id and different values with an array of copies of the first object
Asked Answered
S

4

7

Our GraphQL server responds to a query with data that includes an array of objects each of which shares the same id and different values for a different key. For instance, we might have an array that looks like:

[
  { id: 123, name: 'foo', type: 'bar', cost: 5 },
  { id: 123, name: 'foo', type: 'bar', cost: 6 },
  { id: 123, name: 'foo', type: 'bar', cost: 7 },
  { id: 123, name: 'foo', type: 'bar', cost: 8 }
]

We can see in the Network tab that the response from the server has the correct data in it. However, by the time it goes through processing by the Apollo Client module the array has been transformed into something that might look like this:

[
  { id: 123, name: 'foo', type: 'bar', cost: 5 },
  { id: 123, name: 'foo', type: 'bar', cost: 5 },
  { id: 123, name: 'foo', type: 'bar', cost: 5 },
  { id: 123, name: 'foo', type: 'bar', cost: 5 }
]

Essentially what we're seeing is that if all of the objects in an array share the same value for id then all objects in the array become copies of the first object in the array.

Is this the intended behavior of Apollo Client? We thought maybe it had something to do with incorrect caching, but we were also wondering if maybe Apollo Client assumed that subsequent array members with the same id were the same object.

Studer answered 25/10, 2017 at 17:45 Comment(0)
S
6

It looks like this is behavior as intended. The Apollo Client normalizes on id.

Studer answered 25/10, 2017 at 19:34 Comment(3)
Thanks! This answer saved me hours.Mizell
Here's the reference to the apollo docs github.com/apollographql/apollo-client/blob/master/docs/source/…Mizell
Worth noting: if you query apollo for an id field but don't resolve it - it will return as null for every item, resulting in the same 'normalization'.Jessamine
B
1

As the other answer suggests this happens because Apollo normalises by ID. There's a very extensive article on the official blog that explains the rationale of it, along with the underlying mechanisms.

In short, as seen by Apollo's cache, your array of objects contains 4 instances of the same Object (id 123). Same ID, same object.

This is a fair assumption on Apollo's side, but not so much in your case. You have to explicitly tell Apollo that these are indeed 4 different items that should be treated differently.

In the past we used dataIdFromObject, and you can see an example here.

Today, you would use typePolicies and keyfields:

const cache = new InMemoryCache({
  typePolicies: {
    YourItem: {
      // Combine the fields that make your item unique
      keyFields: ['id', 'cost'],
    }
  },
});

Docs

Barmaid answered 22/3, 2021 at 22:40 Comment(0)
S
1

I have the same issue. My solution is to set fetchPolicy: "no-cache" just for this single API so you don't have to change the InMemoryCache. Note that setting fetchPolicy to network-only is insufficient because it still uses the cache.

fetchPolicy document

Sarmatia answered 26/7, 2022 at 8:55 Comment(0)
Z
0

It works for me: const cache: InMemoryCache = new InMemoryCache({ dataIdFromObject: o => false )};

previous answer solves this problem too! Also you can change the key name(for example id => itemId) on back-end side and there won't be any issue!

Zenia answered 16/9, 2021 at 11:53 Comment(1)
This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From ReviewHyohyoid

© 2022 - 2024 — McMap. All rights reserved.