Vue-apollo: loading is always false

Created on 21 Apr 2018  路  46Comments  路  Source: vuejs/vue-apollo

    <ApolloQuery :query="require('~/apollo/queries/profiles.gql')">
      <template slot-scope="{ result: { loading, error, data } }">
        <div v-if="loading">loading...</div>
        <div v-else-if="error">error</div>
        <b-row v-else-if="data">
          <b-col cols="6" v-for="{ node } in data.profiles.edges" :key="node.id">
            <h3><b-link :to="`${$route.path}/${node.id}`">{{node.name}}</b-link></h3>
          </b-col>
        </b-row>
        <div v-else>no data</div>
      </template>
    </ApolloQuery>

loading is always false
Why?

Most helpful comment

Yeah, weird, only this works for me

<template slot-scope="{ result: {loading, error, data}, isLoading }">
        <div v-if="loading">Loading...</div>

All 46 comments

Are you doing SSR?

yes, with nuxt, no prefetch

We just ran into this as well, and are not doing SSR, everything is client side.

<ApolloQuery :query="require('#/queries/reports.gql')" :variables="{projectId: projectId}">
  <template slot-scope="{ result }">
    {{ result }}
    <div v-if="result.loading">Loading...</div>
    <div v-else-if="result.data">{{ result.data }}</div>
  </template>
</ApolloQuery> 

result.loading is false from start to finish. We've tested on the server with a sleep command, and it's always false.

Looking at the code for ApolloQuery, loading is set to false by default, but then only updated when receiving a message from the smartquery in result. Changing the default loading: false to loading: true fixes the issue for us (loading is true until it finishes loading, then it's false), though I don't know if that's the optimal change.

--- node_modules/vue-apollo/dist/vue-apollo.umd.js  2018-06-20 10:42:53.000000000 -0500
+++ node_modules/vue-apollo/dist/vue-apollo.umd.js  2018-06-20 10:42:56.000000000 -0500
@@ -3629,7 +3629,7 @@
     return {
       result: {
         data: null,
-        loading: false,
+        loading: true,
         networkStatus: 7,
         error: null,
         times: 0

Also ran into this! I'm using the default example that's created in https://github.com/Akryum/vue-cli-plugin-apollo.

  <ApolloQuery
      :query="require('../graphql/HelloWorld.gql')"
      :variables="{ name }"
    >
      <template slot-scope="{ result: { loading, error, data } }">
        <!-- Loading -->
        <div v-if="loading" class="loading apollo">Loading...</div>

        <!-- Error -->
        <div v-else-if="error" class="error apollo">An error occured</div>

        <!-- Result -->
        <div v-else-if="data" class="result apollo">{{ data.hello }}</div>

        <!-- No result -->
        <div v-else class="no-result apollo">No result :(</div>
      </template>
    </ApolloQuery>

When I run the example... It never says loading.. it says No Result :( before the data is loaded..

We found out that using isLoading works, but is it the right way to do?

Yeah, weird, only this works for me

<template slot-scope="{ result: {loading, error, data}, isLoading }">
        <div v-if="loading">Loading...</div>

Having the same problem and can confirm that @coderek solution seems to do the trick. Add a timeout on the server and loading was false from start to beginning. isLoading is however an integer toggling from 1 to 0 instead of a boolean. I haven't been able to find the docs about this "isLoading".

I am experiencing this issue as well, but I'm using the apollo object in my component rather than using the ApolloQuery component. I used the Vue chrome extension to watch the value of loading and just like @micksi found, the loading value never changed.

Another hacky workaround:

  1. Create a data variable 'loading', default it to true.
  2. Create watchers for everything that would make the query refetch, and have the watchers set loading to true
  3. Define the query->update() method and have it set loading to false.

Any fix for this? isLoading doesn't work for me either. Using Nuxt in SPA mode.

Hi, workaround with "isLoading" works.

<template slot-scope="{ result: { loading, error, data }, isLoading }"> <loader v-if="isLoading"></loader>

Can someone make a fix for "loading" that not work properly ?

Thanks

Meet the same problem, some of my components can be works fine with isLoading, some not.

Same problem for me but isLoading works fine

<template slot-scope="{ result: { error, data }, isLoading }"> <div v-if="isLoading" class="loading apollo"> Loading...</div>

I'm using regular routing no SSR

Same issue. Can't get loading to work. Also since I am not using the ApolloQuery component, I don't know how to access isLoading

Any update to this?
not sure if same problem, but for me
Using
const apolloProvider = new VueApollo({ defaultOptions: { $query: { loadingKey: 'loading', } }
generated with default code createProvider()

$apollo fields client, error, loadingKey always undefined
$apollo.loading always false.

I have the same problem. I'm using the component ApolloQuery and I've found that having fetch-policy="cache-and-network" makes the loading var change the state.

Still doesn't work. Is this project abandoned?

Hey Hello @Akryum, love your work on Vue \o/

I encountered the same issue here, loading is always false with my code too , without SSR, just "classic" Vue :

      <ApolloQuery
        :query="require('@/app/graphql/queries/getUsers.gql')"
        :variables="queryVariables"
      >
        <template slot-scope="{ result }">
          <v-card-text>
            <div v-if="result.loading">LOADING...</div>
            <div v-if="result.error">{{result.error}}</div>
            <div v-if="result.data">
              <!--<ListItems items="result.data"/>-->
            </div>
          </v-card-text>
        </template>
      </ApolloQuery>

But using isLoading works fine on below example

      <ApolloQuery
        :query="require('@/app/graphql/queries/getUsers.gql')"
        :variables="queryVariables"
      >
        <template slot-scope="{ result, isLoading }">
          <v-card-text>
            <div v-if="isLoading">LOADING...</div>
            <div v-if="result.error">{{result.error}}</div>
            <div v-if="result.data">
              <!--<ListItems items="result.data"/>-->
            </div>
          </v-card-text>
        </template>
      </ApolloQuery>

I've tried all the suggestions here and still cannot get the loading key to return anything but false without explicitly using fetch-policy="cache-and-network". My expectation was anything but a "cache-only" fetch policy would affect this key which is what the examples seem to imply. My code looks very similar to the previous comment using ApolloQuery components... As stated above isLoading does always work as expected, but it seems odd that the examples in the docs won't work as shown鈥擳his issue was opened almost a year ago now; are there any plans respond to this bug and/or add the information about 'cache-and-network' only to the docs? It seems like it's a point of common confusion looking at these comments. Also, I'm almost certain this was not the case when using the apollo option and dollar apollo before converting to components.

Hey guys, you can just use apollo-client without vue-apollo, it works perfectly fine with Vue.

Here is a small gist for you on of how to use apollo-client : https://gist.github.com/yann-yinn/5a8c00866872251e22ef8acf94188a9f

You can also create very easily your own "declarative component" with apollo-client to call Query like the <ApolloQuery /> one if you want (edit: will try to put an example soon on this thread)

Here is an example of a naive implementation for creating your own ApolloQuery.vue component. ( using apolloClient.js file from the above comment : https://gist.github.com/yann-yinn/5a8c00866872251e22ef8acf94188a9f#file-apolloclient-js )

<!--
If you really like to use apolloClient declaratively, here is a naive implementation
of a custom 'ApolloQuery' component
-->
<template>
  <div>
    <slot name="result" :result="this.result" />
  </div>
</template>

<script>
import apolloClient from '@/app/lib/apolloClient';

export default {
  data() {
    return {
      // some default values until query begin
      result: {
        data: null,
        loading: false,
        networkStatus: 7,
        error: null
      }
    };
  },
  props: {
    query: {
      type: Object,
      required: true
    },
    variables: {
      type: Object,
      required: true
    },
    options: {
      type: Object,
      default: () => ({})
    }
  },
  methods: {
    // you can call this method from outside of the component, using "ref" attribute
    // This is might be useful to relaunch the query after a mutation happened in the parent 
    apolloQuery(variables = {}, options = {}) {
      this.result.loading = true;
      return apolloClient
        .query({
          ...this.options,
          ...options,
          query: this.query,
          variables: {
            ...this.variables,
            ...variables
          }
        })
        .then(result => {
          this.result = result;
        })
        .catch(error => {
          this.result.error = error;
        });
    }
  },
  created() {
    this.apolloQuery();
  },
  watch: {
    variables: {
      deep: true,
      handler: function() {
        this.apolloQuery();
      }
    }
  }
};
</script>

All code is here : https://gist.github.com/yann-yinn/5a8c00866872251e22ef8acf94188a9f

@Akryum can you please fix take a look at this? It's been long pending and having it resolved would mean so much. Thanks :)

Did you try setting notifyOnNetworkStatusChange to true? See apollo docs

@Akryum notifyOnNetworkStatusChange: true does not work. The loading property is still always false.

e.g.,

span(v-if='$apollo.queries.foo.loading') Loading...
apollo: {
  foo: {
    notifyOnNetworkStatusChange: true,
    query: Q_FOO
  }
}

I can confirm that notifyOnNetworkStatusChange: true doesn't solve the issue. And issue shows random failure.

I have the same problem. I'm using the component ApolloQuery and I've found that having fetch-policy="cache-and-network" makes the loading var change the state.

I confirm this solution, did work for me. I've tested it on normal Web App (no Nuxt/SSR stuff).

@Akryum ddce641 did not resolve this issue, I think it needs to be reopened.

I upgraded to vue-apollo@^3.0.0-rc.2 that includes that change, and the reported issue in the OP still exists. The one you fixed looks like a random other issue someone reported as part of this thread.

Here is the problem that still exists:

        <template slot-scope="{ result: { data, loading, error }, isLoading }">
          {{ loading }} <!-- 100% of the time this is FALSE, nothing will change it even in rc.2 -->

I'm pretty sure my patch here https://github.com/Akryum/vue-apollo/issues/263#issuecomment-398798285 is what the real issue is. I was using that patch in production for a while (until we stopped using ApolloQuery components) and it worked perfectly to fix this issue.

I see that it's working there, and I played around with the demo locally and see that it's working as expected. Copying almost identical code locally does not work. The major difference I can see is that you're using vue-cli 3 with the vue-apollo plugin. I'm using a project built with < 2.6 and a manually vue-apollo installation.

Here is a minimally failing example pulled from the demo app:

<template>
  <div>
    <ApolloQuery :query="query">
      <template slot-scope="{ result: { data, loading }, isLoading }">
        <div><tt>Loading</tt> is {{ loading }}</div>
        <div><tt>isLoading</tt> is {{ isLoading }}</div>
        <div v-if="loading" class="loading">
          Loading...
        </div>
        <div v-else-if="data" class="channels">
          {{ data }}
        </div>
      </template>
    </ApolloQuery>
  </div>
</template>

<script>
import gql from 'graphql-tag'

export default {
  name: 'App',
  computed: {
    query () {
      return gql`query user { user { id } }`
    }
  }
}
</script>

You can see from this gif that the loading value is false during the entire duration of the load:

Here's my dependencies (lightly trimmed for obviously unrelated things like dayjs):

  "dependencies": {
    "apollo-cache-inmemory": "^1.6.2",
    "apollo-client": "^2.6.3",
    "apollo-link": "^1.2.12",
    "apollo-link-context": "^1.0.18",
    "apollo-link-error": "^1.1.11",
    "apollo-link-http": "^1.5.15",
    "apollo-link-persisted-queries": "^0.2.2",
    "apollo-link-ws": "^1.0.18",
    "apollo-upload-client": "^11.0.0",
    "apollo-utilities": "^1.3.2",
    "graphql": "^14.2.3",
    "graphql-tag": "^2.10.1",
    "subscriptions-transport-ws": "^0.9.16",
    "vue": "~2.6.10",
    "vue-apollo": "^3.0.0-rc.2",
    "vue-router": "^3.0.1",
    "vuelidate": "^0.7.4"
  },
  "devDependencies": {
    "@babel/preset-typescript": "^7.3.3",
    "@types/apollo-upload-client": "^8.1.2",
    "@types/graphql": "^14.2.3",
    "babel-core": "^7.0.0-bridge.0",
    "babel-loader": "^8.0.5",
    "ts-loader": "5.3.3",
    "typescript": "^3.4.1",
    "vue-loader": "^15.7.1",
    "vue-template-compiler": "~2.6.10",
    "webpack-dev-server": "3.2.1"
  },

I still have this issue with "vue-apollo": "^3.0.0-rc.2"
I'm using ApolloQuery component

fetch-policy="cache-and-network"

and/or

{ result: { loading, error, data }, isLoading }

is fix issue for me
package.json:

  "dependencies": {
    "apollo-cache-inmemory": "^1.6.3",
    "apollo-client": "^2.6.4",
    "apollo-link": "^1.2.12",
    "apollo-link-http": "^1.5.15",
    "apollo-link-ws": "^1.0.18",
    "apollo-utilities": "^1.3.2",
    "axios": "^0.18.1",
    "graphql": "^14.5.3",
    "graphql-tag": "^2.10.1",
    "subscriptions-transport-ws": "^0.9.16",
    "vue-apollo": "^3.0.0-rc.2"
  },

Can confirm the issue. In my case, i need to use fetchPolicy: 'no-cache' and then issue occurs. With no explicit fetchPolicy is everything fine.

To ALL of you. Your problem is, (and im pretty sure), that you are initializing loading as a boolean, as in:
data() { return { loading: false } }
Initialize loading as a number, with a zero, and your problems should go away. The loading property is to hold the number of concurrently running queries (could be more than one), and then cast to bool on your template if you need to.

@DiegoMax Just fyi that is true if you're using the apollo option in the component's script tag but I believe these reports are all referencing using the component; ie scoped slot property of loading. Is there a way to initialize the loading key that way when using the component?

@jeissler, you are right. I checked and i stand corrected, this should be re-opened imho.

I have the same issue using vue-apollo 3.0.0.

As soon as i set fetchPolicy: 'no-cache' the documented loading state feature (https://apollo.vuejs.org/guide/apollo/queries.html#loading-state) does not work anymore and always returns false

Changing fetchPolicy from 'cache-and-network' to 'no-cache' also affects the functionality of loadingKey and watchLoading(isLoading, countModifier) (https://apollo.vuejs.org/api/smart-query.html#options). Both of them are no longer working after the change.

@Akryum

To _ALL_ of you. Your problem is, (and im pretty sure), that you are initializing loading as a boolean, as in:
data() { return { loading: false } }
Initialize loading as a number, with a zero, and your problems should go away. The loading property is to hold the number of concurrently running queries (could be more than one), and then cast to bool on your template if you need to.

So at end of the day, the problem boils down to a simple fact of a situation of misunderstood meaning of the feature provided.

Package developer perspective - loading is number of requests in progress right now
Package user perspective - loading states if the request is loading

Now the issue is, the _loading_ is implicitly provided with the request which as of natural tendency drives user of package to mentioned thought.
Although as of documented by the package developer, we need to have _isLoading_ property additionally which tells about the current request.

Concluding with a suggestion (package developers), to follow the natural tendency and keep _isLoading_ property as is (meaningful name for individual request loading status), just pass it implicitly in place of _loading_ , and let _loading_ be explicitly requested if necessary.

This can be done in a major release.

@vaishnavmhetre

I don't agree that this has anything to do with being a misunderstanding or initializing variables correctly as @DiegoMax proposed.

In the code example below i integrated three documented ways on how to access a loading state (no matter if of type Boolean or Number):

If the option fetchPolicy has the value 'cache-and-network' all three ways work as documented and expected. But as soon as i change fetchPolicy to 'no-cache' none of the three work anymore. And that has nothing to do with being Boolean or not - they don't change their initial value at all and the function watchLoading does not even get called.

So clearly there is something going on with fetchPolicy.

<template>
    <div>
        <h1>Debug</h1>
        <div>$apollo.loading: {{ $apollo.loading }}</div>
        <div>loadingUsingLoadingKeyFeature: {{ loadingUsingLoadingKeyFeature }}</div>
    </div>
</template>

<script>
import USER_QUERY from '@/graphql/User.gql'

export default {
    name: 'DebugUserDetail',
    data () {
        return {
            loadingUsingLoadingKeyFeature: 0
        }
    },
    apollo: {
        user: {
            query: USER_QUERY,
            variables () {
                return {
                    id: 1
                }
            },
            // fetchPolicy: 'cache-and-network',
            fetchPolicy: 'no-cache',
            loadingKey: 'loadingUsingLoadingKeyFeature',
            watchLoading (isLoading, countModifier) {
                console.log('watchLoading')
                console.log('isLoading', isLoading)
                console.log('countModifier', countModifier)
                // isLoading is a boolean
                // countModifier is either 1 or -1
            }
        }
    }
}
</script>

<style scoped></style>

From a distance, looks like an Apollo Client issue 馃

@Akryum Thanks for your feedback!

Could you please explain how this commit is related to this? https://github.com/vuejs/vue-apollo/commit/82d6c02f7b0202d7682007449dfce56de0f5f243#commitcomment-35930431

I currently don't understand why fetchPolicy: 'no-cache' should get a special handling because it does (exclusivly) make network calls and therefore should provide a correct loading state.

I've had this problem and resolved it for myself. Though I'd share my findings.

After digging through the code I found this:
https://github.com/vuejs/vue-apollo/blob/3183cf7f4e0074d46523c2caaa459e8df2b8c4d4/packages/vue-apollo/src/smart-query.js#L104-L110

It would appear that loading is not set when you using the no-cache policy unless the notifyOnNetworkStatusChange option is set to true.

    <ApolloQuery
            :fetch-policy="'no-cache'"
            :query="require('../graphql/some_query.gql')"
            :options="{notifyOnNetworkStatusChange: true}"
    >
      <template v-slot="{ result: { loading, error, data }}">
        <!-- Loading -->
        <div v-if="loading" class="loading apollo">

So I set notifyOnNetworkStatusChange to true and loading started to work as expected. For more details on what this option does check this out: https://www.apollographql.com/docs/react/api/react-hoc/#optionsnotifyonnetworkstatuschange

Hope this helps

@michael-harrison Thanks for your input!

Although setting notifyOnNetworkStatusChange to true makes $apollo.loading behave as documented, it unfortunately triggers all sorts of unwanted behaviour for me, like firing the update function or the result hook many times (once for each network status change i guess). Also like documented at https://www.apollographql.com/docs/react/api/react-hoc/#optionsnotifyonnetworkstatuschange it re-renders your component on every network status change, which you probably also don't really want.

the issue is still there, any solution?

the issue is still there, any solution?

I have mentioned a comment, following works as the solution.

Se if this helps.

Not really a solution tho is it. The value of loading should change independently of notifyOnNetworkStatusChange. As mentioned above, enabling notifyOnNetworkStatusChange triggers unwanted behaviours.

It does seem strange that this happens with no-cache, since with this exact fetchPolicy you always use network requests and checking if they're loading or not should be trivial.

It does seem strange that this happens with no-cache, since with this exact fetchPolicy you always use network requests and checking if they're loading or not should be trivial.

I'm here just to post this issue. I have the same problem with no-cache. Queries with no-cache fetch policy doesn't trigger loadingKey changes.

This works: notifyOnNetworkStatusChange
e.g

<ApolloQuery
    :query="query"
    notifyOnNetworkStatusChange>

  <template v-slot="{ result: { loading, data }}">
   {{loading}}
  </template>

</ApolloQuery>

edit: moved the comment to the similar (but open) issue: https://github.com/vuejs/vue-apollo/issues/501

Was this page helpful?
0 / 5 - 0 ratings