React-apollo: how to understand the usage of dataIdFromObject in 'apollo-cache-inmemory'. Perhaps dont need cache in <Query>?

Created on 14 Sep 2018  ·  3Comments  ·  Source: apollographql/react-apollo

Intended outcome:

[
  {
    id: "1",
    oldRecord: {
      name: "FoodName - 1"
    }
  },
  {
    id: "2",
    oldRecord: {
      name: "FoodName - 2"
    }
  },
  {
    id: "3",
    oldRecord: {
      name: "FoodName - 3"
    }
  }
]

Actual outcome:
It looks like shallow copy in client side. It's fine when http request happens.

[
  {
    id: "1",
    oldRecord: {
      id: "1",
      name: "FoodName - 1"
    }
  },
  {
    id: "2",
    oldRecord: {
      id: "1",
      name: "FoodName - 1"
    }
  },
  {
    id: "3",
    oldRecord: {
      id: "1",
      name: "FoodName - 1"
    }
  }
]

How to reproduce the issue:
https://codesandbox.io/s/vyk3n3rwvl
https://launchpad.graphql.com/nx7rkj9797
Solved:https://codesandbox.io/s/k5pqy4j0z3

Version

  • apollo-client@<2.4.2>
  • react-apollo@<2.1.11>
has-reproduction

Most helpful comment

Hello,

This hasn't to do with shallow copies, it has to do with dataIdFromObject. This is a function that takes a data object and returns a unique identifier to be used when normalizing the data in the store. The ways it does by default is by concatenating the __typename and the id attribute, so the following objects are all considered the exact same object.

dataIdFromObject({ id: "1", name: "FoodName - 1" }) == "FoodRecord_1"
dataIdFromObject({ id: "1", name: "FoodName - 2" }) == "FoodRecord_1"
dataIdFromObject({ id: "1", name: "FoodName - 3" }) == "FoodRecord_1"

This is why if you don't query for the oldRecord id in the codesandbox everything works as expected.
You can solve this by writting a custom dataIdFromObject function like described in the following documentation: https://www.apollographql.com/docs/react/advanced/caching.html#normalization, or making sure the id attribute identifies a unique record.

dataIdFromObject({ id: "1", name: "FoodName - 1" }) == "FoodRecord_1"
dataIdFromObject({ id: "2", name: "FoodName - 2" }) == "FoodRecord_2"
dataIdFromObject({ id: "3", name: "FoodName - 3" }) == "FoodRecord_3"

All 3 comments

Hello,

This hasn't to do with shallow copies, it has to do with dataIdFromObject. This is a function that takes a data object and returns a unique identifier to be used when normalizing the data in the store. The ways it does by default is by concatenating the __typename and the id attribute, so the following objects are all considered the exact same object.

dataIdFromObject({ id: "1", name: "FoodName - 1" }) == "FoodRecord_1"
dataIdFromObject({ id: "1", name: "FoodName - 2" }) == "FoodRecord_1"
dataIdFromObject({ id: "1", name: "FoodName - 3" }) == "FoodRecord_1"

This is why if you don't query for the oldRecord id in the codesandbox everything works as expected.
You can solve this by writting a custom dataIdFromObject function like described in the following documentation: https://www.apollographql.com/docs/react/advanced/caching.html#normalization, or making sure the id attribute identifies a unique record.

dataIdFromObject({ id: "1", name: "FoodName - 1" }) == "FoodRecord_1"
dataIdFromObject({ id: "2", name: "FoodName - 2" }) == "FoodRecord_2"
dataIdFromObject({ id: "3", name: "FoodName - 3" }) == "FoodRecord_3"

Thanks for your explaination.
I used MySQL and used the primary key id.
I try to change the client side InMemoryCache.dataIdFromObject. But it seems InMemoryCache is meaningless.

const client = new ApolloClient({
  cache: new InMemoryCache({
    dataIdFromObject: object => null
  })
});

https://codesandbox.io/s/k5pqy4j0z3

The cache is a part of the apollo-client project. Quentin has the explanation right, you need a globally unique I'd which not only would include your MySQL I'd but also the type (table name).

Was this page helpful?
0 / 5 - 0 ratings