Using React Query with TypeScript
Tags: webdev, react, typescript
Published: 2023-07-11 20:32:51

When retrieving data from an API (application programming interface) in React, it's always important to do so in the most suitable way for your application. But because there's more than one way to do it, it proves to be problematic. (Throw in TypeScript and it gets even more complicated.) Many developers have acquainted themselves with React Query, a library that simplifies data fetching and state management.

## More Resources
- [React Query documentation](https://tanstack.com/query/v4/docs/react/overview)
- [TypeScript documentation](https://www.typescriptlang.org/docs/)

Using TypeScript with React Query takes the developer experience further by ensuring that the request and response from the API is properly defined. Plus, it saves you from unprecedented runtime errors that JavaScript may not notice. Let's try fetching some data from an online fake API.

First, we install the React Query package (for data fetching) and the Axios package (for making HTTP requests).

```
npm i @tanstack/react-query axios
```
Say we want to get all posts from the API. That means we are making a GET request. When we look at the response, it's an array of objects like this:

```
[
  {
    "userId": 1,
    "id": 1,
    "title": "Mary had a little lamb",
    "body": "Mary had a little lamb whose fleece was white as snow."
  },
  ...
]
```

From this data, we can create an TypeScript interface to infer what type of data we're looking to receive. It'll look something like this:

```
interface Posts {
  userId: number;
  id: number;
  title: string;
  body: string;
}
```

In our component, we create an asynchronous function to make the request. Asynchronous functions always return a Promise, but we will take advantage of TypeScript by infering the `Posts[]` type on the Promise. This ensures that TypeScript knows what kind of data we're going to get.

```
const getPosts = async (): Promise<Posts[]> => {
  const posts = await axios.get('https://jsonplaceholder.typicode.com/posts')?.data;
  return posts;
}

```

Now we can make proper use of React Query by using the `useQuery` hook. 

```
const {data, isLoading, isError} = useQuery({
  queryKey: ['get-posts'],
  queryFn: getPosts
})
```

Note that we destructured the hook into an object with the properties above.
- `data` represents the response from the API call.
- `isLoading` is a boolean value which is `true` when there is no ongoing query attempt.
- `isError` is a boolean value which is `true` when there was an error fetching the query.

There are many more properties we can use for different functions, but we'll stick with these three for this example.

Given the `isLoading` and `isError` properties, we can decide what to render to the browser at each state of the data fetching process. Here's what the whole code looks like:

```
export default function Posts() {
  const getPosts = async (): Promise<Posts[]> => {
    const posts = await axios.get('https://jsonplaceholder.typicode.com/posts')?.data;
    return posts;
  }
  const {data, isLoading, isError} = useQuery({
    queryKey: ['get-posts'],
    queryFn: getPosts
  })

  if (isLoading) {
    return <div>Loading posts...</div>
  }

  if (isError) {
    return <div>Oops!</div>
  }

  return (
    <div>
    {data?.map((post) => (
      <p key={post.id}>{post.body}</p>
    ))}
    </div>
  )
}
```

It's important to note that when familiarizing yourself with a library, the documentation is the best place to begin. There you can discover more techniques to solving a problem and how to apply them in different use cases.