GraphQL apollo caching query that has no id

46 Views Asked by At

I'm writing an app that is using anilist graphql backend. This backend provides a pagination with Page query. So the paginated query itself looks like that:

  1. For Anime screen:
    query ($page: Int, $perPage: Int) {
      Page (page: $page, perPage: $perPage) {
        media (type: ANIME) {
          id
          title {
            romaji
          }
        }
      }
    }
  1. For Manga screen:
    query ($page: Int, $perPage: Int) {
      Page (page: $page, perPage: $perPage) {
        media (type: MANGA) {
          id
          title {
            romaji
          }
        }
      }
    }

In my app there two screens Manga and Anime they both sends this query but with different type (ANIME or MANGA). And at this point I faced a problem. Page query has no id so it's impossible split in cache Page query for ANIME and Page query for MANGA. Pagination will also affect this problem as each time user reach the end of list I will send a new Page query. As I can see it should work in the next way:

  1. Page query for ANIME and for MANGA should be separated in cache in other words cache should somehow know that they are different objects.
  2. On response for a next page request I should merge media in Page of MANGA or in Page of ANIME.

Do you have any ideas how to obtain such functionality? For now I consider an option to clear cache on screen change, that will allow me to avoid a first part of problem, cache will always contain just one Page query. But then the second part of problem will stay. On each new page obtained Page in cache will be just overwritten.

2

There are 2 best solutions below

0
Stas Motorny On

So I found a way to satisfies my requirements. It includes 2 steps:

  1. I to ApolloClient I added typePolicies like that:
typePolicies: {
    Query: {
        fields: {
            Page: {merge: true},
        },
    },
},
  1. Added updateQuery that describes how exactly cache should be changed on fetchMore:
fetchMore({
    variables: {
        ...updateQueryVariable(searchQuery, sortType),
        page: pageNumber,
    },
    updateQuery: (prev, {fetchMoreResult}) => {
        if (!fetchMoreResult) {
            return prev;
        }
        return {
            ...prev,
            Page: {
                ...prev.Page,
                media: [
                    ...(prev.Page?.media as Media[]),
                    ...(fetchMoreResult.Page?.media as Media[]),
                ],
            },
        };
    },
});

As result I got the cache like this: enter image description here

So now apollo cache for Page contains the results separated by type ANIME or MANGA. The only thing is that, as I found, updateQuery is deprecated, so not sure how long this approach will be valid.

0
phry On

There are two approaches here:

  • One would be to add a field policy for your media field with keyArgs

  • The other way of doing this would to use a @connection` directive in your query.