How can I cache nested objects with Apollo Client?

How can I cache nested objects with Apollo Client?


3

I’m using the Contentful GraphQL API to fetch a collection of items, in this example football clubs.

query Clubs($limit: Int!, $skip: Int!) {
    clubCollection(limit: $limit, skip: $skip) {
        total
        items {
            name
            description
        }
    }
}

The structure of the response is:

clubCollection: {
  items: [{
    ... array of all the clubs
  }]
}

It looks like the Apollo InMemoryCache is only caching the full query in its ROOT_QUERY object. But not each individual club. The setup for the cache looks like this:

new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        clubCollection: concatContentfulPagination()
      },
    },
  },
})

Does anyone know how I can target the clubs in items so that I can cache each individual club?

EDIT:
Thanks to the answer from @xadm I realised I did not need to extend the InMemoryCache like so:

new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        clubCollection: {
          items: { 
          
          },
          ...concatContentfulPagination()
        }
      },
    },
  },
})

But instead add it to the root of the typePolicies based on the type of the object, for me it is Club. When I added that it did work!

new InMemoryCache({
  typePolicies: {
    Club: {
      keyFields: ['name']
    },
    Query: {
      fields: {
        clubCollection: concatContentfulPagination()
      },
    },
  },
})

Share
Improve this question

0

2 Answers
2

Reset to default


2

Items should have an id prop requested … to be normalized – Apollo is normalizing cache GraphQL client

It’s required to cache entries/types/subtypes properly.

https://graphql.org/learn/caching/

It, unique key can be id, _id or customized key per type using typePoliciescustomizing-identifier-generation-by-type.

https://www.apollographql.com/docs/react/caching/cache-configuration/#default-identifier-generation

In this case (no queryable id prop inside items), you should check in API (docs/specs/schema or explore network response body – __typename prop of items object) the type of club items entries (probably Club) and customize cache policies like:

new InMemoryCache({
  typePolicies: {
    Club: {
      keyFields: ['name']
    },

… assuming name is unique.

Share
Improve this answer

3

  • Thanks for your answer. I was aware the object needs an ID, unfortunately the id of a Contentful object is in a ever deeper nested object: graphql clubCollection(limit: $limit, skip: $skip) { total items { sys: { id } name description } } So maybe my question was wrong… The question would be, how can I access the array of clubs in items with typePolicies to set the field name for example as the keyFields?

    – Lingertje

    Mar 12, 2021 at 11:51


  • You should see individual item entries in the cache … you can use cache API (readFragment) to read them … what do you mean by 'how can I access the array of clubs' ? items array is a prop of response type (query returns some typed item? unknown? check __typename in network response details? check api/specs, (no id, not normalized)

    – xadm

    Mar 12, 2021 at 12:49

  • Thanks again! I editted the original post with what I think is the solution. Is that indeed what you tried to tell me? 🙂

    – Lingertje

    Mar 12, 2021 at 12:55


0

For this pupose you can use reactive variables. That way you can access clubs array anywhere in your code without rerunning query and perform any array operation on it.
Visit this page for more info on it.

Share
Improve this answer



Leave a Reply

Your email address will not be published. Required fields are marked *