DEV Community

Cover image for Configuring useQuery Hook
Nischal Dutt
Nischal Dutt

Posted on • Edited on

Configuring useQuery Hook

Now that we have a basic understanding of useQuery hook, let's understand various ways through which we can configure our queries using the useQuery hook.

useQuery(key, function, { options go here }):
Enter fullscreen mode Exit fullscreen mode

Lets dive in

cacheTime

Let's try re-fetching the query results without useQuery hook first i.e. with a simple useEffect hook.

data fetching with useEffect

You’ll notice, that every time we do a re-fetch, the loading state is encountered each time. This shows the results are not being cached and as a result, a hard reload happens for that particular query.

Now let us try this re-fetch with useQuery hook. You'll notice below that the loading state is not encountered every time a re-fetch occurs. This indicates that query responses are being cached by React-Query by default.

data fetching with useQuery

You can also view the cached content maintained by navigating to Query.cache.queries[0].state.data in the Query explorer section of devtools.
cacheTime takes in number of milliseconds a query responses must be saved in the cache after which, the cache will be cleared and the query will be re-fetched automatically in the background.
By default, cachTime is set to 5 minutes.
How cool is that! All the cache management is done by React-Query itself.

You might wonder how will we come to know if the background re-fetch is being done because the isLoading flag is not getting changed. For this specific reason React Query provides another flag isFetching which indicates the background fetching status of the query.
Also for re-fetching, a refetch function is returned that performs automatic re-fetch itself.

Below is the updated version of our code:

import React from "react";
import { useQuery } from "@tanstack/react-query";

async function fetchCompanies() {
  return await fetch(`http://localhost:4000/companies`).then((response) =>
    response.json()
  );
}

const Companies = () => {
  const {
    isLoading,
    data: companies,
    isError,
    error,
    isFetching,
    refetch,
  } = useQuery(["companies"], fetchCompanies, {
    cacheTime: 5000, // cache will be cleared after 5 seconds
  });

  if (isLoading) {
    return <h1>loading</h1>;
  }

  if (isError) {
    return <h1>{error.message}</h1>;
  }

  return (
    <div>
      {companies.map((company) => {
        return <h1 key={company.id}>{company.name}</h1>;
      })}
      <button onClick={refetch}>refetch</button>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Note that, isFetching indicates the background re-fetch status while isLoading indicates the normal ones.

staleTime

staleTime helps reduce the network requests to the server.

We specify staleTime in milliseconds after which the response from the query should be considered stale i.e. not fresh anymore.

By default staleTime is set to 0 milliseconds.

useQuery(["companies"], fetchCompanies, {
    staleTime: 10000,
});
Enter fullscreen mode Exit fullscreen mode

For instance, consider the above call, the staleTime is 10 seconds, and the response will be marked fresh for the first 10 seconds, after which it will become stale.

fresh data for first 10 seconds

data becomes state after stateTime

So any changes in the list of companies for the first 10 seconds will not be reflected and no matter how many times we hit /companies endpoint no new network request will be generated, but once data becomes stale after 10 seconds updated list of companies will be fetched again in the background.

refetchOnMount

This option as the name suggests specifies whether to trigger re-fetch automatically when every time the component mounts. It can have 3 values:

  • true: re-fetches on mount of the component only if the data is stale
  • false: does not re-fetches on mount even if data is stale
  • always: re-fetches every time on mount of the component irrespective of whether data stale or not.

The default value is set to true and in most cases, it is best suited as well.

refetchOnWindowFocus

As the name suggests, a re-fetch occurs on focus of the window. This is similar to refetchonMount and the values are same as well.

useQuery(["companies"], fetchCompanies, {
    refetchOnMount: true,
    refetchOnWindow: true,
  });
Enter fullscreen mode Exit fullscreen mode

refetchInterval

Sometimes we want to fetch the results from a query in regular intervals i.e. polling, we can do that by specifying the interval in milliseconds to this attribute.

Also by default, polling or automatic re-fetching is paused when the window loses focus, to prevent that from happening we can provide another config option called refetchIntervalInBackground and set it to true.

useQuery(["companies"\, fetchCompanies, {
    refetchInterval: 5000,
    refetchIntervalInBackground: true,
  });
Enter fullscreen mode Exit fullscreen mode

Here query will be fetched every 5 seconds irrespective of whether window is focused or not.

Can it get more easier than this!!? :)

enabled

You might have noticed as soon our component mounts the query is fetched and we get the results, but what if we want to trigger the fetch only if we click a button. enabled prop will let us do that. By default it it set to true.

const Companies = () => {
  const {
    isLoading,
    data: companies,
    isError,
    error,
    isFetching,
    refetch,
  } = useQuery(["companies"], fetchCompanies, {
    enabled: false
  });

  if (isLoading) {
    return <h1>loading</h1>;
  }

  if (isError) {
    return <h1>{error.message}</h1>;
  }

  return (
    <div>
      {companies?.map((company) => {
        return <h1 key={company.id}>{company.name}</h1>;
      })}
      <button onClick={refetch}>fetch</button>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

We use refetch function, pass it as an onClick handler to the button, and set enabled to false.
You can notice from devtools that initially when the component renders, the query key is marked as disabled hence no network request is triggered.

key is disabled

but when we click on the fetch button, the network request is fired and data is fetched.

enabled query

success and error callback

After fetching the response from the query you might want to perform some side effects based on whether the query was successful or not. For this react query provides success and error callbacks which will run automatically after the query fetch is complete and thus, we can perform any sideEffects.

const onSuccess = (data) => {
    console.log(
      "performing the side-effect after successful fetch with response ==> ",
      data
    );
  };

  const onError = (error) => {
    console.log("encounter an error during fetching ==> ", error);
  };

  const { isLoading, data: companies, isError } = useQuery(
    ["companies"], 
    fetchCompanies, {
      onSuccess,
      onError,
    });
Enter fullscreen mode Exit fullscreen mode

callbacks called

It is evident from above that, data and error objects are implicitly injected in onSuccess and onError callbacks respectively.

select

In select we define a function that is used to transform the data to our desirable format. For instance when we fetch the companies array, the response object looks like

{
   "id": 3,
   "name": "Apple",
   "founder": "Steve Jobs"
}
Enter fullscreen mode Exit fullscreen mode

Now suppose we want to print the founders instead of company names, we can transform the array of company objects to array of founders using select function

const { isLoading, data, isError} = useQuery(["companies"], fetchCompanies, {
    select: (data) => {
      const founders = data.map((company) => company.founder);
      return founders;
    },
  });
Enter fullscreen mode Exit fullscreen mode

Now the data returned from the useQuery hook will have only array of founders. We can perform manipulation like filtering, reducing an array etc as per our requirements.


Thank you for reading!

In the next section, we'll learn about some approaches for querying the data, which are pretty common in web development and we'll see how easy React Query makes it for us to handle such situations.

Feel free to reach out to me! 😊

💻 Github ✨ Twitter 💌 Email 💡Linkedin

Till then happy coding!

Top comments (0)