javascriptreactjsreact-query

How to use Lazy query with React-query?


I am using React-query for my API calls. I am wondering if there is a way to call the query in a lazy way.

Meaning to call the query only when a query param changes.

This is what I currently have; I am using a hack with the useEffect where if recipeName changes, then run the refetch function.

export const searchRecipeByName = async (recipeName: string) => {
  return await api.get(
    `/recipes/complexSearch?apiKey=${process.env.NEXT_PUBLIC_SPOONACULAR_API_KEY}&query=${recipeName}&addRecipeInformation=true&fillIngredients=true`
  );
};
  const [recipeName, setRecipeName] = useState("");

  const { data, refetch } = useQuery(
    "homePageSearchQuery",
    () => searchRecipeByName(recipeName),
    { enabled: false }
  );

// HACK
  useEffect(() => {
    if (!!recipeName) {
      refetch();
    }
  }, [recipeName]);

  const handleOnSearchSubmit = async (recipeSearch: RecipeSearch) => {
    setRecipeName(recipeSearch.search);
  };

Preferably, I would like to call the query in the handleOnSearchSubmit function.

I could create a custom useLazyQuery hook to handle this, but I'm wondering if React-query has a native way to handle this.


Solution

  • Preferably, I would like to call the query in the "handleOnSearchSubmit" function.

    This is a quite imperative way of thinking about things, but react-query is more declarative. You don't specify: "when I click that button, I want to fetch", but you just say: "these are the inputs I require" and react-query will refetch whenever those inputs change.

    So what you want to do is put the things that you need for your query to run into the query key, so that react-query

    const [recipeName, setRecipeName] = React.useState('')
    const { isLoading, data } = useQuery(
      ['homePageSearchQuery', recipeName],
      () => searchRecipeByName(recipeName),
      {
        enabled: !!recipeName
      }
    ])
    

    then, all you need to do is call setRecipeName in handleOnSearchSubmit, and react-query will do the querying.

    some more things that you might want to consider:

    const [recipeName, setRecipeName] = React.useState('')
    const debouncedRecipeName = useDebounce(recipeName, 1000)
    const { isLoading, data } = useQuery(
      ['homePageSearchQuery', debouncedRecipeName],
      () => searchRecipeByName(debouncedRecipeName),
      {
        enabled: !!debouncedRecipeName
      }
    ])
    

    This will let you input data and show it in a text field, but only creates a new cache entry / fires a new request after 1 second of inactivity.