Running Apollo Angular watchQuery() with different variables return the cache data

2.3k Views Asked by At

So, I am working on a project's feature that allows users to view data based on different variables, for example, data that are unique to years, location, gender etc.

Below is the code that I write:

 this._querySubscription = this._apollo.watchQuery({                      
      query: *some graphql query*,
      variables: {
        // this is where the variables are dump 
      }
    })   
    .valueChanges        
    .subscribe(( { data, loading } ) => { 
      do something with the data                            
    })    

Now, don't worry about the error with the function and stuff because I have got everything right. I even have below code to handle cache and even evict.

let cache = this._apollo.client.cache as InMemoryCache
      
        let data = this._apollo.client.cache.readQuery({
          query: *some graphql query*,
          variables: { *using the same variables as the writeQuery, of course*}  
        })
        
        cache.evict({
          fieldName: "*the fieldname from the query*", 
          broadcast: false,
        }); 
        
        this._apollo.client.cache
        .writeQuery({
          query: *some graphql query which is the same as above*,
          data,
          variables: {
            *again, same variables*      
          }  
        })

Some of the things that I have come across are:

  1. Without using the readQuery and writeQuery, when running the watchQuery again, even with different variables to run the query will return the same data from the cache.
  2. Using the readQuery, writeQuery, evict and running the second query with different variables will not return the same data from the cache (which I am looking for) but, if I try to run the first query back, the data return will be empty, probably because I modify the cache. 3.If you are thinking of using fetchPolicy when running the query, I have tried all 4 fetchPolicy , cache-first, network-only etc. It works if I use cache-network-only but then somehow I have no idea how to wait for it completely finish making the request and updating the cache before I can update my UI.
2

There are 2 best solutions below

1
On

I had the same problem as well when using Apollo. They way I solved was to create a separate module that handle all the Graphql stuff with a Factory, and a no-cache on the .watchQuery method. I'm sure you can change fetchPolicy to accept one of these values: 'cache-first' | 'network-only' | 'cache-only' | 'no-cache' | 'standby' | 'cache-and-network' (Values take from watchQueryOptions.d.ts).

I'm using the latest version of the packages:

"@apollo/client": "^3.2.4",
"apollo-angular": "^2.0.4",
"graphql": "^15.3.0",

So, here's the module:

import { NgModule } from '@angular/core';
import { InMemoryCache } from '@apollo/client/core';
import { Apollo, APOLLO_OPTIONS } from 'apollo-angular';

import { HttpLink } from 'apollo-angular/http';

export function createApollo(httpLink: HttpLink) {
    return {
        link: httpLink.create({
            uri: "/api/...",
            withCredentials: true
        }),
        cache: new InMemoryCache(),
        credentials: 'include',
    };
}

@NgModule({
    exports: [],
    providers: [
        {
            provide: APOLLO_OPTIONS,
            useFactory: createApollo,
            deps: [HttpLink],
        },
    ],
})

export class GraphQLModule {
    constructor(
        apollo: Apollo,
        httpLink: HttpLink
    ) {
        apollo.create({
            link: httpLink.create({
                uri: "/api/...",
                withCredentials: true
            }),
            cache: new InMemoryCache()
        }, "network");
    }
}

tsconfig.json file needs to be edited with these versions by adding this line: "allowSyntheticDefaultImports": true under compilerOptions

Then I call the query in a component:

this.apollo
    .watchQuery({
        query: your_query,
            variables: {
                ...your_variables
            },
            returnPartialData: false,
            fetchPolicy: "no-cache" // <----- You may need to change that as I wrote above

        }).valueChanges
        .subscribe((data: any) => {
          foo();
        });
0
On

I just solved a similar issue you were having and the trick was to call this._querySubscription.refetch(newVariables). That way you shouldn't have to manually delete cache.