vuejs / apollo

🚀 Apollo/GraphQL integration for VueJS
http://apollo.vuejs.org
MIT License
6.03k stars 522 forks source link

Cached result is not instantly returned when `fetchPolicy` is set to "cache-and-network" #1315

Open MCYouks opened 2 years ago

MCYouks commented 2 years ago

Describe the bug When settings the query options with { fetchPolicy: "cache-and-network" }, the cached result is not instantly returned.

Instead, it waits until the data is fetched from the server to return the result.

To Reproduce Steps to reproduce the behavior:

  1. Setup useQuery with the following options { fetchPolicy: "cache-and-network" }
  2. Setup 2 query variables: variables1 and variables2
  3. Execute the query with variables1, then variables2, then variables1 again — e.g. const { result } = useQuery(query, variable1, { fetchPolicy: "cache-and-network" })
  4. On the second time you query with variables1, the change in result won't be instantaneous. Instead, it will wait for a few seconds before updating.

Expected behavior The cached result should be returned instantly.

Versions vue: "^3.2.16" @vue/apollo-composable: "^4.0.0-alpha.16" @apollo/client: "^3.5.8"

Kakahn commented 2 years ago

We have identified the same issue.

In the meantime, for this to be corrected, it would seem that if we add

notifyOnNetworkStatusChange: true,

at the useQuery level it works. But impossible to put it at the level of the config of apollo in defaultOptions.

Wait and see :)

productdevbook commented 2 years ago

some problem

tafelnl commented 2 years ago

notifyOnNetworkStatusChange: true does fix it for fetching the query the first time. But if your component refetches the query (because of reactive variables changing or whatever), it will have the same issue again. So it's a workaround for some simple use cases, but definitely not for all use cases (and it's pretty common to use reactive variables in queries).

ishitatsuyuki commented 2 years ago

If you're affected by this, could you please try #1388? You can setup linking manually or put "@vue/apollo-composable": "npm:@ishitatsuyuki/apollo-composable@4.0.0-alpha.19.usequery-stale" in your package.json. Let me know if it fix (or does not fix) your issues!

xvaara commented 2 years ago

@ishitatsuyuki fixes the issue for me.

tafelnl commented 2 years ago

Heads up: there's now a release that ships the fix of @ishitatsuyuki https://github.com/vuejs/apollo/releases/tag/v4.0.0-beta.1

Narretz commented 2 years ago

This is fixed in vue-apollo 4.x, but the same logic exists in vue-apollo 3.x, see:

https://github.com/vuejs/apollo/blob/fdc6fb869202e49cd1194a71876394a742deed1d/packages/vue-apollo/src/smart-query.js#L115-L123

Removing the code also fixes the issue, but I found that at least in 3.x, the code does something.

Consider the following:

with the above code, the child component has the cached data before the component tries to render the template. Without the code, it doesn't (and you have to use v-if etc. to wait for the data)

This brings me to the point that vue-apollo is still not well tested.

As long as the testing strategy is subpar, errors like this will pop up again and again.

viljark commented 1 year ago

I ended up patching the @vue/apollo-option directly inside vue-apollo-option.esm.js for now, I'm not 100% sure of the logic, but it solved the issue for us with "cache-and-network" not returning any cached results. Also network-only and cache-only seemed to work as expected.

diff --git a/node_modules/@vue/apollo-option/dist/vue-apollo-option.esm.js b/node_modules/@vue/apollo-option/dist/vue-apollo-option.esm.js
index e5a7f2f..efb1d95 100644
--- a/node_modules/@vue/apollo-option/dist/vue-apollo-option.esm.js
+++ b/node_modules/@vue/apollo-option/dist/vue-apollo-option.esm.js
@@ -783,7 +783,8 @@ var SmartQuery = /*#__PURE__*/function (_SmartApollo) {
         var currentResult = this.retrieveCurrentResult();
         if (this.options.notifyOnNetworkStatusChange ||
         // Initial call of next result when it's not loading (for Apollo Client 3)
-        this.observer.getCurrentResult && !currentResult.loading) {
+          (this.observer.getCurrentResult && this.options.fetchPolicy !== 'network-only') ||
+          (this.observer.getCurrentResult && this.options.fetchPolicy === 'network-only' && !currentResult.loading)) {
           this.nextResult(currentResult);
         }
       }