React Apollo cache set up, refetch, refetchQueries and fetchPolicy explained with examples

The mistakes I made with Apollo cache and how I fixed it

May Chen
NEXL Engineering
4 min readJul 20, 2020

--

If you use Apollo for your GraphQL project, setting up cache can come in very handy and provider a smoother experience for your users.

Imagine this scenario, you visit your personal page on Medium for the first time, the client will query the server for a list of articles you have published and it takes 0.3s before you can see your articles . And you leave your personal page and visit the home page to browse popular articles, then somehow you come back to your personal page again, does the client have to query the server again this time? Do you have to wait for another 0.3 second?

The answer is no if you have set up cache in your Apollo client. And you really should because imagine again your project gets super popular and at one moment you have one million users online browsing around, do you want the one million of them query the server 3 times for the same result when it can be done once and the result will be stored at their end and their computing cost? Now if you are onboard with why you want to set up Apollo cache, let’s get started.

Set up Apollo cache

Setting up Apollo cache is super simple, create a new InMemoryCache instance and pass it in to your client.

import { ApolloClient, InMemoryCache } from '@apollo/client';

const client = new ApolloClient({
uri: 'https://48p1r2roz4.sse.codesandbox.io',
cache: new InMemoryCache()
});

Read more on configuring Apollo cache here.

Problem 0: What if the result gets updated?

Things run so smoothly with Apollo cache, it doesn’t take ages for the query result to come back anymore, but before long I had my first bug.

Say we are on a article listing page again and we click on “create new article” button, a modal pops up. We put in an new article and click on “publish”, the client sends a mutation to the server with the article and the modal disappears. Now the article is published but why doesn’t the list update?

Because the client doesn’t know it needs to update the article list query. How can we let the client know?

Two ways.

refetch

refetch is a function to refresh query result from Apollo query.

const { loading, error, data, refetch } = useQuery(GET_ARTICLES);

So our solution is to refetch article list after publishing a article. To put it in the code, we simple have refetch from article list query as the onCompleted function in publish article mutation.

const [publishArticle] = useMutation(PUBLISH_ARTICLE, {
variables: { newArticle },
onCompleted: refetch,
});

Read more on refetch here.

refetchQueries

The above solution looks a little tedious, especially if the mutation and query are not in the same component and we have to pass the refetch function to the component where the mutation is.

Here is a simpler solution, with refetchQueries in Apollo mutation, you can specify the queries you want to run after the mutation is completed.

import {GET_ARTICLES} from "/blabla/../queries"const [publishArticle] = useMutation(PUBLISH_ARTICLE, {
variables: { newArticle },
refetchQueries: [GET_ARTICLES],
});

Read more on refetchQueries here.

Problem 1: refetchQueries doesn’t seem to work for queries on another route

There is one problem I have with refetchQueries, it doesn’t seem to work when the queries are on another route.

Say we have articles list on route /articles, and create new article on a different route /articles/new, in this case even when I have refetchQueries: [GET_ARTICLES] in my mutation in the NewArticle component, the articles don’t get updated when I visit /articles afterwards.

To this date I still can’t figure out why it doesn’t work, but I have found a workaround for this issue — fetchPolicy.

Apollo client’s default fetch policy is cache-first, which means it will try to find the result in cache first, serve it to the user if it’s available and doesn’t really care if the cache has latest update.

And if we specify fetchPolicy to cache-and-network in the article list query, the client will serve the cache to the user first when it’s available but at the same time check with server if there’s any updates to the result.

const { loading, error, data, refetch } = useQuery(GET_ARTICLES,{
fetchPolicy:"cache-and-network"
});

This solution is a nice balance between smooth experience that users can see the cached result first without waiting and accurate result, which then updates to the UI. It does increase the cost and make more network calls, but it is here to stay before I find out why refetchQueries doesn’t work for other routes.

Read more on fetchPolicy here.

--

--

May Chen
NEXL Engineering

A developer who occasionally has existential crisis and thinks if we are heading to the wrong direction, technology is just getting us there sooner.