Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apollo Client cache

I just started using apollo client on a React application and I'm stuck on caching. I have a home page with a list of products where I do a query to get the id and name of those products and a product page where I do query for the ID, name, description and image.

I would like that if a user visits the home page fist then a specific product page to only do a query for that product's description and image, also display the name during the loading (since I should have cached it already). I followed "Controlling the Store" part of the documentation (http://dev.apollodata.com/react/cache-updates.html) but still couldn't resolve it.

The query that is done when we go to the product page still asks for both the product's id and name whereas they should be cached since I already asked for them.

I think I'm missing something but I can't figure it out. Here is a bit of the code:

// Create the apollo graphql client.
const apolloClient = new ApolloClient({
    networkInterface: createNetworkInterface({
        uri: `${process.env.GRAPHQL_ENDPOINT}`
    }),
    queryTransformer: addTypename,
    dataIdFromObject: (result) => {
        if (result.id && result.__typename) {

            console.log(result.id, result.__typename); //can see this on console, seems okey
            return result.__typename + result.id;
        }

        // Make sure to return null if this object doesn't have an ID
        return null;
    },
});

// home page query
// return an array of objects (Product)
export default  graphql(gql`
   query ProductsQuery {
        products {
            id, name
        }
    }
`)(Home);

//product page query
//return an object (Product)
export default graphql(gql`
   query ProductQuery($productId: ID!) {
        product(id: $productId) {
            id, name, description, image
        }
    }
`,{
    options: props => ({ variables: { productId:  props.params.id } }),
    props: ({ data: { loading, product } }) => ({
        loading,
        product,})
})(Product);

And my console output:

console output

like image 391
Frolanta Avatar asked Nov 04 '16 16:11

Frolanta


2 Answers

The answer to your question actually has two parts:

  1. The client cannot actually tell for sure that these queries resolve to the same object in the cache, because they have a different path. One starts with products, the other with product. There's an open PR for client-side resolvers, which will let you give the client hints about where to find things in the cache, even if you haven't explicitly queried for them. I expect that we will publish that feature within a week or two.

  2. Even with client-side resolvers, Apollo Client won't do exactly what you described above, because Apollo Client no longer does query diffing since version 0.5. Instead, all queries are fully static now. That means even if your query is in the cache partially, the full query will be sent to the server. This has a number of advantages that are laid out in this blog post.

You will still be able to display the part that's in the cache first, by setting returnPartialData: true in the options.

like image 62
helfer Avatar answered Oct 19 '22 20:10

helfer


This question is quite old, however, there is a solution to map the query to the correct location using cacheRedirects

In my project, I have a projects query and a project query.

I can make a cacheRedirect like below:

const client = new ApolloClient({
  uri: "http://localhost:3000/graphql",
  request: async (operation) => {
    const token = await localStorage.getItem('authToken');
    operation.setContext({
      headers: {
        authorization: token
      }
    });
  },
  cacheRedirects: {
    Query: {
      project: (_, { id }, { getCacheKey }) => getCacheKey({ id, __typename: 'Project' })
    }
  }
});

Then when I load my dashboard, there is 1 query which gets projects. And then when navigating to a single project. No network request is made because it's reading from the cache 🎉

Read the full documentation on Cache Redirects

like image 25
Karl Taylor Avatar answered Oct 19 '22 21:10

Karl Taylor