Querying data using React Query
Tags: javascript, react, reactnative, beginners
Published: 2022-10-02 10:09:50

## Querying By Id

Now that we know about working with `useQuery` hook and its configuration options to fetch the data, we can move forward to what is also pretty common operation i.e. to fetch any particular item details from a list of items based on its `id`.
Consider another endpoint `/companies/:id` that returns clicked company details.

```jsx
<h1 key={company.id}>
	<Link to={`/companies/${company.id}`}>{company.name}</Link>
</h1>
```

```jsx
import React from "react";
import { useParams } from "react-router-dom";
import { useQuery } from "@tanstack/react-query";

const fetchCompany = (id) => {
  return fetch(`http://localhost:4000/companies/${id}`).then((response) =>
    response.json()
  );
};

const Company = () => {
  const { id } = useParams();
  const {
    isLoading,
    data: companyData,
    isError,
    error,
  } = useQuery(["company", id], () => fetchCompany(id));

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

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

  return (
    <div>
      <h2>{companyData.name}</h2>
      <h2>{companyData.ceo}</h2>
    </div>
  );
};

export default Company;
```

Let us understand what happened above,
First we define the `fetchCompany` function that takes in the `id` of the company, fetches the company details, and returns it.
Second, To get the clicked company’s id we can use `useParams` hook provided by `react-router-dom` that returns an object which contains all URL parameters, we just destructed id param.

Now lets look at the `useQuery` hook,

```jsx
const {
  isLoading,
  data: companyData    
  isError
} = useQuery(["company", id], () => fetchCompany(id));
```

The hook has minor changes, the query key now constitutes of a string key and id param, this helps to uniquely identify the query. So the key takeaway from this is that the query key here is `["company", id]`.

Now in the second argument, we provide the callback function with the company id.

Result

![querying by id using useQuery](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u6f1n9t4x25fgnywk71c.gif)

It works! 

Notice how we’re passing the `id` to the `fetchCompnay` function in the callback. Their’s an aleternative way to achieve that without passing the `id` in the callback in the `useQuery` hook. 

React-Query will pass some meta information and query key as arguments to the fetch function **implicitly**, so in the fetch function we can de-structure the appropriate arguments to get the id of the company.

Since the query key is an array which gets passed in the `queryKey` props, from there we can get the `id` of the company.

```jsx
const fetchCompany = ({ queryKey }) => {
  const id = queryKey[1];
  return fetch(`http://localhost:4000/companies/${id}`).then((response) =>
    response.json()
  );
};

const {
  isLoading,
  data: companyData    
  isError
} = useQuery(["company", id], fetchCompany);
```

## Dynamic Parallel Queries

Now that we know how to fetch an item based on its `id`, consider a scenario where the requirement is to fetch multiple items based on their respective ids parallelly. Most developers (including me) might think of putting the useQuery hook in a loop and calling it multiple times but that is not something that is allowed as it violates the rule of hooks i.e. **they cannot be called inside any conditional statements or for loops**.

Hence to tackle this specific scenario react query provides a hook called `useQueries`, lets see how it works

```jsx
import { useQueries } from "@tanstack/react-query";

const componyIds = [1, 2, 3];

const response = useQueries({
  queries: componyIds.map((id) => {
    return {
      queryKey: ["company", id],
      queryFn: fetchCompany,
      staleTime: Infinity
    };
  })
});
```

The `useQueries` hook accepts an `options` object with a queries key whose value is an array with query option objects identical to the `useQuery` hook

![dynamic parallel queries](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3hws7uizsbk0ght49vwb.png)

All queries run in parallel and a response is returned only after all companies are fetched.


## Dependant Queries

Now that we know how to handle multiple queries **parallely**, we are also going to come across scenarios where we have to fetch the data **sequentially** i.e. when one query is dependent on another query before it can fetch the data.

Dependent (or serial) queries depend on previous ones to finish before they can execute. To achieve this, it's as easy as using the `enabled` option to tell a query when it is ready to run.

For this case let's say we have `/githubUsers` endpoint which returns a list of Github users, where each user being:

```jsx
{
	"id": "jack@gmail.com",
	"githubId": "gf6ds5g4d5sf1g65dsf"
},
```

and we have `/githubRepositories` endpoint which returns the user data like:

```jsx
{
  "id": "gf6ds5g4d5sf1g65dsf",
  "repositories": [
    "jack/react",
    "jack/next",
    "jack/angular",
    "jack/vue"
  ]
}
```

This is a simple scenario where dependent queries come into the picture. We cannot fetch the user repositories until we have the id of the user.

Using `enabled` config we choose **to pause the execution of a query until the desired data is available**.

```jsx
const fetchGithubUser = ({ queryKey }) => {
  const userEmail = queryKey[1];
  return fetch(`http://localhost:4000/githubUsers/${userEmail}`).then(
    (response) => response.json()
  );
};

const fetchRepositories = ({ queryKey }) => {
  const userId = queryKey[1];
  return fetch(`http://localhost:4000/githubRepositories/${userId}`).then(
    (response) => response.json()
  );
};

const GihubUserRepos = () => {
	const userEmail = "jack@gmail.com";
	const { data: user } = useQuery(["github-user", userEmail], fetchGithubUser);

	const githubUserId = user?.githubId;
	const { data: userData } = useQuery(
	  ["github-user-data", githubUserId], fetchRepositories, {
	    enabled: !!githubUserId,
		  }
		);

	const userRepos = userData?.repositories;
	console.log({ userRepos });
	
	return (
		<div>
			// map through the list of userRepos
		</div>
	);
```

Notice how we first fetch the Github user based on an email which in turn will not be immediately available so we use optional chaining to get the user id.

While fetching the repositories we provide the `enabled` config with value `!!githubUserId`, **we use double negation to convert the `id` to a boolean value**.

![dependant queries using enabled](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x8h2abokwyiypkhg10q6.gif)

Initially, the user id is not available when the component mounts hence `userId` is kept as `null`, and react query tracks the query as `disabled`. Then once the `githubId` is available, that is used to fetch the user repositories.

That’s how dependant queries are managed by React Query.


---

## Thank you for reading!

In this lesson, we went through a couple of ways using which we can tackle different data fetching problems that developers face while building applications.

In the next lesson, we will go through some advanced concepts which can enhance and improve the overall data fetching/viewing experience for users.

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!