Re-fetching A Vue Apollo Smart Query While Showing A Loading Indicator

I ran into a situation where I needed to re-fetch a Vue Apollo smart query while showing a loading indicator. At first, I thought the smart query's $apollo.queries.[QUERY_NAME].loading property was surely the way to go. But for some reason, this property doesn't get updated when the $apollo.queries.[QUERY_NAME].refetch() method gets called.

Anyway, this is how I was able to get it to work;

<template>
  <div class="posts">
    <template v-if="isFetchingPosts">
      <div class="loading-indicator">Loading...</div>
    </template>
    <div v-for="post in posts" :key="post.id" class="post-item">
      <h2 class="post-title">{{ post.title }}</h2>
      <div class="post-content">{{ post.content }}</div>
    </div>

    <button type="button" :disabled="isFetchingPosts" @click="refetchPosts">
      Re-fetch Posts
    </button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      posts: [],
      isFetchingPosts: false
    }
  },

  apollo: {
    posts: {
      query: gql`
        query PostsQuery($offset: Int!, $limit: Int!) {
          posts(offset: $offset, limit: $limit) {
            id
            title
            content
          }
        }
      `,

      variables() {
        return {
          offset: 0,
          limit: 50,
        }
      },

      result({ loading }) {
        this.isFetchingPosts = loading
      },
    }
  },

  methods: {
    refetchPosts() {
      this.$apollo.queries.posts.refetch()
    }
  }
}
</script>

The trick here is using the result hook which receives an object with a loading property as its first argument. This loading properly indicates whether the query is loading or not. We then use the value to update the isFetchingPosts variable defined in our data method.

The loading property in the object that gets passed to the result hook gets updated when the query is loading for the first time and when the this.$apollo.queries.posts.refetch() method gets called. Which is exactly what we want.

Alright then. That's it for this one. I have a feature implementation to finish.✌🏽