React Query 101
Tags: react, javascript, reactquery, web
Published: 2021-02-09 23:54:06

---
title: React Query 101
published: true
description: A simple intro to react-query
tags: react, javascript, reactquery, web
//cover_image: https://direct_url_to_image.jpg
---
I've always looked at `react-query` from far away, before I was mainly working with GraphQL and Apollo was a great solution for my querying needs.

Fast forward a couple years and now I am at a different job and I am not using GraphQL anymore. Having heard a lot about react-query I decided to give it a try and see how good it really is.

And...

*Insert drum roll*

It's actually pretty great, it has all the goodies I enjoyed in Apollo and it's not restricted to GraphQL.

Here is a quick guide to demonstrate some of the many benefits/features of react-query.

First let's create a react project, create-react-app is perfect for this simple demo app.
```bash
npx create-react-app react-query --template typescript

# or

yarn create react-app react-query --template typescript
```

*Yes, I am adding TypeScript to this one page application, I can't deal with those yellow icons anymore*

Now navigate inside the `react-query` folder that was just created.

If you are in the terminal just do
```bash
cd react-query
```

Now let's install `react-query`

```bash
 npm i react-query
 # or
 yarn add react-query
```

Let's also install `axios` to use it instead of `fetch`
```bash
 npm i axios
 # or
 yarn add axios
```

Now inside `src/App.tsx` past the following code
```jsx
import React from 'react';
import './App.css';

function App() {
  return (
    <div className="App">
      <h1>Random Food Generator</h1>
      <button>Generate</button>
      <img src="insert food url here" 
        alt="food"/>
    </div>
  );
}

export default App;
```

So the promise of this app is pretty simple, we press a button to get a randomly generated dish. In order to do this we will use the [food api](https://foodish-api.herokuapp.com/) ,react-query and axios.

First we need to wrap our in app inside a `<QueryProvider />` to connect the `queryClient`.

Inside `src/index.tsx` let's import `QueryClient` and create a new client for the app.

```jsx
// ...other code

import { QueryClient, QueryClientProvider } from "react-query";

// ...other imports

const queryClient = new QueryClient();
```

And let's use the `QueryClientPovider` with the new client we just created.

Still inside `src/index.tsx`
```jsx
ReactDOM.render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>
  </React.StrictMode>,
  document.getElementById("root")
);
```

And that's all we need to start firing our queries!

### The magic of useQuery

Hooks are here to stay and most of my favorite libraries are using them, `react-query` is no exception. The `useQuery` hook is pretty cool, we give it a unique key and a function that returns a promise. In exchange we get the data and other useful props.

Let's see in action, inside `src/App.tsx` let's add the following code.

First let's import `useQuery` and `axios`.
```jsx
import { useQuery } from "react-query";
import axios from "axios";
```

Now inside the `App` component let's use `useQuery`

```jsx
  const { data } = useQuery("food", () =>
    axios.get("https://foodish-api.herokuapp.com/api/")
  );
```

and now in the JSX
```jsx
 return (
    <div className="App">
      <h1>Random Food Generator</h1>
      <button>Generate</button>
      <img src={data?.image} alt="food" />
    </div>
  );
```

So far so good, everything seems to work, but if you pay attention you may notice some strange behavior. For example if you go to another tab in your browser, when you come back the query is re-fetched. This is one of the things that caught me off guard when trying `react-query` for the first time, I remember not having a clue of what was going on and just switching to something else.


Well, apparently it's important to read the docs. `react-query` has some  [defaults](https://react-query.tanstack.com/guides/important-defaults)  that can be aggressive but you can easily change them to what you need or you are used to.

These are my defaults.
```jsx
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 3600,
      refetchOnWindowFocus: false,
    },
  },
});
```

So now we are not re-fetching on window focus and we actually have a stale time.

Besides `data` we have access to other props that can help us build a better UI by telling us the state of the query.

Let's take a look.
```jsx
const { data, isFetching, isError, refetch } = useQuery("food", () =>
    axios.get("https://foodish-api.herokuapp.com/api/")
  );
```

There are more, but we will use these for now. I think these props are pretty self explanatory, let's use them to let the user know what's going on with the query.

```jsx
function App() {
  const { data, isFetching, isError, refetch } = useQuery("food", () =>
    axios.get("https://foodish-api.herokuapp.com/api/")
  );

  if (isError) {
    return <p>Oops an error happened</p>;
  }

  return (
    <div className="App">
      <h1>Random Food Generator</h1>
      <button type="button" onClick={() => refetch()}>
        Generate
      </button>
      {isFetching ? (
        <p>Loading...</p>
      ) : (
        <img src={data?.data?.image} alt="food" />
      )}
    </div>
  );
}
```

So first we check for any errors, then connect the button to the refetch function and finally display a loading state when the image is being fetched.

Can we do all of these with `fetch`?
Yeah of course, but it would have taken a lot more code. A `useEffect` for fetching the initial data,  creating state for the loading and error, and putting everything into a function to do the re-fetch.

This is only scratching the surface of what `react-query` can do, we didn't even look into the cache how it can replace state management tools like redux.

Anyways, I hope this got you interested in checking  [`react-query`](https://react-query.tanstack.com/), because there is so much more that you can do.

Over and out.

Code: https://github.com/ivanms1/react-query-101

PS: Miss you GraphQL :(