Configuring useQuery Hook
Tags: webdev, javascript, react, usequery
Published: 2022-09-29 19:02:24

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.

```jsx
useQuery(’key’, function, { options go here }):
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/waxaqoqn3drk98kydxb0.gif)


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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/08ibs5wwd7vr6ktyh8vj.gif)


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:

```jsx
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>
  );
};
```

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. 

```jsx
useQuery(["companies"], fetchCompanies, {
    staleTime: 10000,
});
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/25uqg9lkmcp4dsu93uo9.png)


![data becomes state after stateTime](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2ffhum3543lpxhusjamk.png)

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.

```jsx
useQuery(["companies"], fetchCompanies, {
    refetchOnMount: true,
    refetchOnWindow: true,
  });
```

## **`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`.

```jsx
useQuery(["companies"\, fetchCompanies, {
    refetchInterval: 5000,
    refetchIntervalInBackground: true,
  });
```

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.

```jsx
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>
  );
};
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8by43bjoq4k8ywvwlcev.png)

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


![enabled query](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v7czf78nqs2u2sdpfpy8.gif)

## **`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.

```jsx
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,
    });
```

![callbacks called](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ac867sy9tro5grdf2b5u.gif)

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

```jsx
{
   "id": 3,
   "name": "Apple",
   "founder": "Steve Jobs"
}
```

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

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

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](https://github.com/nischaldutt) [✨ Twitter](https://twitter.com/nischal_dutt) [💌 Email](mailto:nischaldutt01@gmail.com) [💡Linkedin](https://www.linkedin.com/in/nischal-dutt) 

Till then happy coding!