npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

use-cache-network-query

v1.0.8

Published

Apollo Client useQuery with cache-and-network that only returns loading if no cache

Downloads

12

Readme

use-cache-network-query npm version

The problem

You're using Apollo Client useQuery for fetchPolicy 'cache-and-network' that checks the cache before refetching in the background, but you still always get a loading spinner showing until the network query returns.

This is a wrapper around useQuery that returns loading as false if you have a cache.

Now the loading should work as you expect, your UI will not show a loading spinner if there is cache and then when the network query completes Apollo will re-render the component for you.

Example

From the Apollo docs - Setting a fetch policy, replace:

const { loading, error, data } = useQuery(GET_DOGS, {
  fetchPolicy: 'cache-and-network',
  // other options
});

if (loading) {
    return (...)
}

with:

const { loading, error, data } = useCacheNetworkQuery(GET_DOGS, {
  // other options
});

if (loading) {
    return (...)
}

That's it, useQuery -> useCacheNetworkQuery and remove fetchPolicy option.

Why

Apollo's useQuery defaults to only ever checking the cache if it exists. This is via the fetchPolicy that is 'cache-first'.

In my opinion, if you have a normal size app (tens not hundreds of queries), then dealing with the impact of a fetchPolicy of 'cache-first' for a list of items has a massive overhead. You have to:

  1. Handle cache from add and delete mutations
  2. Handle any cached queries using variables for add and delete mutations
  3. Handle any server side changes

You have to add this boilerplate for every single one of your list item queries.

You can do all that or just add this to your useQuery options:

{
  fetchPolicy: 'cache-and-network'
}

As per the Apollo docs:

Apollo Client executes the full query against both the cache and your GraphQL server. The query automatically updates if the result of the server-side query modifies cached fields.

Provides a fast response while also helping to keep cached data consistent with server data.

The problem with this is that if you have a loading spinner, the query sets loading to true even though it is fetching directly from the cache. So if you have

if (loading) {
    return (...)
}

then the loading spinner will show, whilst the network fetch is happening even though useQuery fetches immediately from the cache.

This makes the UX as if you had { fetchPolicy: 'network-only' } and you completely lose the 'fast response' suggested by the docs.

This hook returns loading true only if there is no cache. Then Apollo handles the re-render once the network request updates the cache.

Inspiration

This problem is perfectly explained in apollographql/apollo-client #8669, with the code for this from a workaround comment by @puglyfe. The impact of the very simple switch, turns a completely non-reactive app that shows a loading spinner on every page load, to being the reactive app you expect, that loads once and then is instantaneous.

There's practically no code here, but it was such a jaw dropping moment for me to finally see React + Apollo cache working correctly that I wish Apollo did this by default. There is a reasonable explantion in the issue above why they don't, but I think its worth spreading this to get my sanity back for dealing with Apollo caching.