T
TanStackβ€’3y ago
rare-sapphire

Does anyone have an example for using debounce with React query?

I am using Zustand to save the search term
const searchTerm = AutoCompleteStore.useSearch((state) => state.searchTerm);
const updateTerm = React.useRef(AutoCompleteStore.useSearch((state) => state.updateTerm));
const searchTerm = AutoCompleteStore.useSearch((state) => state.searchTerm);
const updateTerm = React.useRef(AutoCompleteStore.useSearch((state) => state.updateTerm));
And then
const debouncedSearchTerm: string = useDebounce(searchTerm, 500);

// react query
Search.useAutoComplete(debouncedSearchTerm);
const debouncedSearchTerm: string = useDebounce(searchTerm, 500);

// react query
Search.useAutoComplete(debouncedSearchTerm);
Input
<input
value={searchTerm}
onChange={onSearch}
/>
<input
value={searchTerm}
onChange={onSearch}
/>
Onsearch
const onSearch = React.useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.value.length > 0) {
updateTerm.current(e.target.value);
} else {
clearTerm.current();
}
},
[],
);
const onSearch = React.useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.value.length > 0) {
updateTerm.current(e.target.value);
} else {
clearTerm.current();
}
},
[],
);
But still, the query triggers every keystroke. Any idea what would be the correct implementation. Many thanks in advance πŸ™πŸ½
20 Replies
sensitive-blue
sensitive-blueβ€’3y ago
I'm not an avid Zustand user but would it make more sense to debounce the function that performs the update instead?
rising-crimson
rising-crimsonβ€’3y ago
Could you post the code of useAutoComplete? Is it Zustand specific or a custom hook?
rare-sapphire
rare-sapphireOPβ€’3y ago
Thank you, so much for your response from you two πŸ™‚ Again poor from my end; I have <Results /> component to display the results. I was using the same query in the <Results /> component but was passing the "searchTerm" from the store, which is "undebounced" version of the search term.
const searchTerm = AutoCompleteStore.useSearch((state) => state.searchTerm);
const { data, isInitialLoading, isError } = Search.useAutoComplete(searchTerm);
const searchTerm = AutoCompleteStore.useSearch((state) => state.searchTerm);
const { data, isInitialLoading, isError } = Search.useAutoComplete(searchTerm);
Basically, two components use the same query, one using the debouncedSearchTerm whereas the other is using searchTerm from the store (which is the culprit). Removing the useQuery or passing the same debouncedSearchTerm for the <Results /> component fixed the issue. This is my very first time with React-Query. All looks great to me. But the only mindset change I find difficult is using the same query in multiple components but with the provision of API fetching just the parent component and the rest of the places more of listeners query. A query for listening would be a great addition. Query that comes with fetch.
useQuery<QueryResponse, Failure>({
queryKey: ['search-autocomplete', searchTerm],
queryFn: getSearchResults
})
useQuery<QueryResponse, Failure>({
queryKey: ['search-autocomplete', searchTerm],
queryFn: getSearchResults
})
Query with the same query key that is just for fetching the stale data; no fetching is required or Should be disabled unless the parent query is available with the data
useStaleQuery<QueryResponse, Failure>({
queryKey: ['search-autocomplete', searchTerm],
})
useStaleQuery<QueryResponse, Failure>({
queryKey: ['search-autocomplete', searchTerm],
})
Is this possible with the setup?
rare-sapphire
rare-sapphireOPβ€’3y ago
queryFn looks optional from the typings available. But getting Missing queryFn in the console durning runtime 😦
No description
rising-crimson
rising-crimsonβ€’3y ago
In RQ, a query is a set of data linked to a key, with a way to fetch/refetch them. As soon as you have different data or different key, then it is ANOTHER query. In your case, you want a query for EACH search term (debounced or not). Once this query is there, this means that the data for this search term are there and can be shared by other components. So by default, a query is both in "fetching mode" and in "listener mode". With this query, wrap in a custom useSearch hook, you could re-use it everywhere. - if data are there, then immediately available - otherwise queryFn would be called to retrieve them
useQuery<QueryResponse, Failure>({
queryKey: ['search-autocomplete', searchTerm],
queryFn: getSearchResults
})
useQuery<QueryResponse, Failure>({
queryKey: ['search-autocomplete', searchTerm],
queryFn: getSearchResults
})
rare-sapphire
rare-sapphireOPβ€’3y ago
Thanks @glabat, for your detailed response. If I use the same query with the same key in ten places, RQ is smart enough to fire just one request to the server, right?
sensitive-blue
sensitive-blueβ€’3y ago
If there's data in the cache that isn't stale then yeah πŸ‘
rare-sapphire
rare-sapphireOPβ€’3y ago
Great πŸ‘
rising-crimson
rising-crimsonβ€’3y ago
Yep that is exactly the purpose of RQ πŸ˜‰ Also if not already the case I suggest to add the RQ dev tools to your app to « seeΒ Β» the queries and how they live
rare-sapphire
rare-sapphireOPβ€’3y ago
Yeah sure keen to set that up πŸ‘Œ tha ks again both ❀️
rising-crimson
rising-crimsonβ€’3y ago
Also did you define a staleTime for your queries ? The default one is 0 meaning that as soon as data are returned from queryFn, they are considered as stale and the next time the query is used, a new call would be made. As such you should consider having a reasonable staleTime for your usecase. How long do you want the data returned for a given search to be considered as relevant?
rare-sapphire
rare-sapphireOPβ€’3y ago
I have set it as Infinity β™Ύ 😁 Elastic search is configured to update once in 10 days, so absolutely fine with infinity πŸ™‚
rising-crimson
rising-crimsonβ€’3y ago
πŸ‘
rare-sapphire
rare-sapphireOPβ€’3y ago
Sorry I missed your message about sharing the β€˜useAutoComplete’ fn. It's same as you recommended, a separate hook for the use query.
sensitive-blue
sensitive-blueβ€’3y ago
That should work nicely for you πŸŽ‰ let us know if you run into anything else πŸ™‚
rising-crimson
rising-crimsonβ€’3y ago
I just wanted to make sure that the debounced term was part of the query key πŸ˜…
sensitive-blue
sensitive-blueβ€’3y ago
This might be worth a read: https://tkdodo.eu/blog/react-query-fa-qs#how-can-i-pass-parameters-to-refetch I know it's not exactly what you were trying to do but the explanation for why you can't refetch with different parameters might clarify a few things to do with queries and their keys
rare-sapphire
rare-sapphireOPβ€’3y ago
Yeah I am reading all his post on this regard πŸ™‚
sensitive-blue
sensitive-blueβ€’3y ago
Dominik's blog is fantastic, there's so much knowledge in it :reactquery:
rare-sapphire
rare-sapphireOPβ€’3y ago
Absolutely gold standard πŸ†

Did you find this page helpful?