apollo icon indicating copy to clipboard operation
apollo copied to clipboard

useLazyQuery behaves like useQuery when the the query is a subset of previous one

Open rimutaka opened this issue 2 years ago • 1 comments

Example of variables:

{
  startsWith: searchFilter.value
}

where searchFilter.value is a state property from a Pinia store (a reactive object).

If the value of searchFilter is increasing in length (the user is typing new characters) useLazyQuery waits for load() to be called, but if the user hits backspace and the length of the value is decreasing the query fires off automatically without load() being called as if it was useQuery, not a lazy one.

Here is a sequence of values for searchFilter.value logged via watch and their corresponding effect on useLazyQuery:

m <-- none
mo <-- none
mong <-- none
--> at this point load() is called and the query is successfully executed
mongo <-- none
mongodb <-- none
--> at this point load() is called again and the query is successfully executed for the second time
mongod <-- the query executes on its own
mongo <-- the query executes on its own
mong <-- the query executes on its own
... and so on until the value is blank

To Reproduce

const store = useQueryStore(); // Pinia store
const { searchFilter } = storeToRefs(store); // needed to make watch work on a store property

// needed to track calls by useLazyQuery - returns the variables
function searchFilterLocal() {
  console.log(`searchFilterLocal: ${searchFilter.value}`);
  return {
    startsWith: searchFilter.value,
  };
}

// the actual useLazyQuery execution part
const { result, loading, error, load } = useLazyQuery(
  keywordSuggesterQuery,
  searchFilterLocal,
  store.defaultApolloOptions
);
  1. Set searchFilter.value to a string of 3-4 chars long
  2. call load()
  3. Add more characters to searchFilter.value - there should be no query execution while doing that
  4. Start removing characters from the end of the string one by one - the query will fire up without load() being called

Expected behavior The query should not execute unless load() is called.

Versions

  "dependencies": {
    "@apollo/client": "^3.5.10",
    "@vue/apollo-composable": "^4.0.0-alpha.16",
    "graphql": "^16.3.0",
    "graphql-tag": "^2.12.6",
    "pinia": "^2.0.11",
    "vue": "^3.2.31",
  },

Additional context There is a lot more code involved in my case. I am reasonably certain this problem is not caused by the extra code, but I can make a minimal reproducible example if the above description is not sufficient.

rimutaka avatar Jun 12 '22 01:06 rimutaka

The problem has resolved itself after I changed the query variables to a local Ref like this:

const queryVars: Ref<keywordSuggesterQueryVars> = ref({ startsWith: "" });

const { result, loading, error, load } = useLazyQuery(
  keywordSuggesterQuery,
  queryVars,
  store.defaultApolloOptions
);

const debounceload = debounce(2000, () => {
  // some code that moves user input to queryVars
  // and calls load()
}

With the above approach no matter what changes to startsWith I tried they never triggered the query execution without an explicitly called load().

@Akryum , not sure it's worth your time digging into this problem. Feel free to close the issue.

Do you want a PR to add some docs and examples to useLazyQuery? It's not very obvious to novices like myself when and how to use that one. Happy to help.

rimutaka avatar Jun 12 '22 02:06 rimutaka