Instead of debouncing the queryFn, debounce the search parameters. This ensures that the query function is called only when the debounced search parameters change.

Step-by-Step Implementation

1. Create a Debounce Hook

First, create a `useDebounce` hook to return a debounced value that updates only after a specified delay.

import { useState, useEffect } from 'react';
function useDebounce(value, delay) {
    const [debouncedValue, setDebouncedValue] = useState(value);

    useEffect(() => {
        const handler = setTimeout(() => {
        }, delay);
        return () => {
    }, [value, delay]);

    return debouncedValue;
export default useDebounce;

2. Use the Debounce Hook in Your Component

Here’s an example using a todo list.

import { useState } from "react";
import { useQuery } from "react-query";
import useDebounce from "./useDebounce";

function useTodos(page, search) {
  let url = `${page}`;
  if (!!search) {
    url += `&q=${search}`;

  return useQuery(
    ["todos", { page, search }],
    () => fetch(url).then((res) => res.json())
export default function Todos() {
  const [page, setPage] = useState(0);
  const [search, setSearch] = useState("");
  const debouncedSearch = useDebounce(search, 500);

  const { isFetching, isError, data, error } = useTodos(page, debouncedSearch);

  function handleSearchChange(event) {

  function handlePageChange(event) {

const availablePages = [...Array(11).keys()].slice(1);
  return (
{isFetching ? (
) : isError ? (
Error: {error.message}
) : ( { => ( ))}
# Title Completed?
{} {todo.title} {todo.completed ? "yes" : "no"}
); }


  1. Creating the Debounce Hook: The useDebounce hook takes a value and a delay. It sets a timeout to update the debounced value after the specified delay. If the value changes before the delay, the previous timeout is cleared, and a new one is set.
  2. Using the Debounce Hook in the Component: In the Todos component, useDebounce is used to debounce the search and page values. These debounced values are then used as part of the query key in useQuery.
  3. Fetching Data with Debounced Parameters: The useTodos function fetches data using the debounced parameters, ensuring that the API call is made only when the debounced values change.

By debouncing the search parameters rather than the `queryFn`, you ensure that useQuery receives a defined value and avoids the issue of a debounced function not returning a value immediately. This approach leverages the built-in caching and state management features of React Query while optimizing performance with debounce.

Support On Demand!