React Query - The Definitive Guide to Making Requests in React
Tags: javascript, react, codenewbie
Published: 2023-09-17 10:37:29


### You might have been fetching data in your React Apps WRONG ❌

React itself does not have any opinions about how we fetch data from the Server.

![react meme](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tyt1fdp5lxc25pq77ro1.gif)

The most commonly used are FetchAPI and the Axios library. 

## Wrong Approach 1 : Fetch API 🎣
This is the most basic approach to use the Browser's Fetch API. 

It is called when a component first mounts, using the `useEffect` hook and manage the response with `useState`. But, this is not the recommended way for good developers(not even the best ones).

Fetch is not a good option because of : 
- A lot more code is required for simple tasks.
- Lack of any useful functionality that makes the developer experience very bad.

![React with Fetch Sample](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t6wyzkic2ehttuzhk2kp.png)


## Wrong Approach 2 : Axios 🪓
The Axios library simplifies the above code a bit, but still lacks some features for a great developer experience. 

It abstracts the code for fetching, but does not help in : 
- Caching.
- Data states like Error or loading.
- Still has try-catch hell.

![React with Axios Sample](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fjeuticojwhp5dj1z4ty.png)

Now that the above 2 magical ways are wrong, what is the correct way?

## React Query - A Library that simplifies the way we fetch, cache and synchronize data from a server

![Tanstack Query](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3vtpje9uqw2p5xmstnpz.png)

Yes, both of the above are the same thing. 

Let's see what React Query or Tanstack Query does and is in detail. 

### It is not Just A Data Fetching Library
What React Query gives you is not just the ability to describe which data you want and to fetch that data, it also comes with a cache 🧠 for that server data. 

This means that you can just use the same `useQuery` hook in multiple components, and it will `only fetch data once and then subsequently return it from the cache`.
![React Query](https://media.giphy.com/media/iibOQywHqFLsW8ziXb/giphy.gif)

## Enough with the theory, show me the Code ⌨
Now, let's see how to set it up and some use cases where React Query just feels awesome.

## Setup (The Boring Part)
First of all you need to have a project setup, either in `ReactJS` or in `NextJS`. 
I will just use React Query in my [Lynkit🔗](https://github.com/thevinitgupta/Lynkit) project.

To add React Query to the project, we use the following command : 
```shell
npm i @tanstack/react-query
```

Now if you have used something like `Redux` or `ContextAPI` before, you have to make the client available to all the parts that you will be using.

The simplest way to do this is by wrapping the parts of your application inside a `client-provider`, which in this case is called the `QueryClientProvider`.

We also need to create a client which handles all the functionality of the Library.

> [!Important] 
> Client is nothing but an instance of the base class of React Query in this case. It handles all the functionalities that we want to use. 

For my project(an in most cases), I want to access the `QueryClient` from all scopes of the `App`, so we wrap the whole App component inside it.

```tsx
import {
  QueryClient,
  QueryClientProvider,
} from '@tanstack/react-query'

const queryClient = new QueryClient()

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </QueryClientProvider>
  </React.StrictMode>
);
```
Now that React Query is Setup, it is time to look at it's various use cases.

## Fetching Data
When making a Get Request, we use the `useQuery` hook provided by the React Query library. 

> Note : If hooks are something you don't understand, I want you to stop here and look at this : [Hooks : JS in plain english](https://javascript.plainenglish.io/react-hooks-the-complete-guide-5c176ca825f6) by Ayush Verma.

Okay, so useQuery hook. 
Queries are basically asynchronous requests tied to a data source. And async requests are handle by promises in Javascript. 

So, the `useQuery` hook are used to subscribe to a query that listens to the `pending`, `fulfilled` and `rejected` states and returns a state based on that.

A lot of jargon? Yeah, agreed. So here's a diagram : 

![Use Query Subscription](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fd6z9bjlpvqxkwr5yxlt.png)

> ### Now the hooks take in 2 parameters mainly : 
> - A unique key 🔑 for the query
> - A function that returns a promise that:
>      - Resolves the data ✅ , or
>      - Throws an error ❌

### 📢 The `unique key` you provide is used internally for `refetching, caching, and sharing` your queries throughout your application.

Let's see an example from Lynkit where I fetch the logged in user data :
### The Actual Data Fetching using Axios.get()
Yes, for fetching data we have to use Axios but not directly. 
We define a function to get the data and add it as a Query Function to the **User** key. 

So, whenever I want to use the User data, I can just use the UseQuery hook to get the user data : 
- If found in the Query cache, it returns the data from there.
- Other it calls the following function : 
```ts
export const getUserData = async() : Promise<ProfileData> => {
    try {
      const response : AxiosResponse = await axios.get("http://localhost:3003/user", {
        headers : {
          "Content-Type" : "application/json",
        },
        withCredentials: true,
      });
      const {status, data } = response;
      console.log(data)
      if(status!==200 || !data.user){
        ...
        return nullUser;
      }
      return data.user as ProfileData;
      
    } catch (error) {
      console.log(error);
      throw new Error("Data Fetching Failed")
    }
}
``` 

The UseQuery hook is used as follows : 
```tsx
const {data, isError, isLoading} = useQuery<ProfileData>(
    {
      queryKey : ["user"],
      queryFn : getUserData,
      notifyOnChangeProps : ['data','error'],
      refetchOnWindowFocus: false
    }
  )
```
The above works as follows : 
Step 1 : Read the Query Key passed, in this case : `["user"]`
Step 2 : Check if query key is present in the `Query Cache` and return if present.
Step 3 : If the data is not present in the cache, called the function passed in the `queryFn` property.

## 📌 Note that `useQuery` hook is used only for `get ↩` requests. For other requests like, we use the `useMutation` hook with the mutate method.

## Invalidating Queries ❗📛
There will be cases, where you want to re-fetch data when an action occurs.
React Query also provides a way for us to do that : `client.invalidateQueries()` method.

You need to pass in the same `queryKey` that you want to be re-fetched and the QueryClient auto fetches the data when that data is invalidated.

```tsx
const queryClient = useQueryClient();
queryClient.invalidateQueries(["user"]);
```
The cached user data is removed and the new data from API or server is fetched again at this point.

The above can be used in 2 conditions : 
- The data is updated by adding, editing or deleting some part(like updating user name or password or image).
- `Logging out ❌` the user.

At this point you are ready to develop a sophisticated query based application. 

For more detailed and complete explanations, you can check out @tkdodo 👈 profile and the [Complete Tanstack Docs 💡](https://tanstack.com/query).

You can also checkout my previous blog on [Bun - Fastest Javascript Runtime ⚡](https://dev.to/thevinitgupta/discover-bun-a-faster-modern-javascript-runtime-5fob)