HomeAbout MeContact

Getting Started With React-Query

By Sai Kranthi
Published in React
August 22, 2021
3 min read
Getting Started With React-Query

What is React Query?

According to their official Docs,

React Query is often described as the missing data-fetching library for React, but in more technical terms, it makes fetching, caching, synchronizing, and updating server state in your React applications a breeze.

It basically maintains the cache of server data on the client. All you need to do is to let react query know when it needs to refresh the data in the cache.

With React Query you get,

  • Loading or Error states when you fetch the data from the server.
  • Pagination, handled by react query
  • Prefetching
  • Mutation
  • Deduplication of request
  • Retry on error

And a few other interesting stuff. Let’s look into how we can get started with this amazing library.

Prerequisites

We assume that you already know the basics of React and React Hooks .

Installation and Setup

Create a new react project using the command

npx create-react-app my-app

This is my setup

Let’s install react query using the command below,

npm install react-query

or

yarn add react-query

Create a new file with the name Todos.js and the following code and mount it in App.js

import React from "react";

export default function Todos() {
  const data = [{ userId: 1, title: "Buy groceries", id: 1, completed: false }];

  return (
    <>
      <ul style={{ listStyle: "none" }}>
        {data?.map((todo) => (
          <li
            key={todo.id}
            style={{ color: todo.completed ? "green" : "orange" }}
            className="todo-title"
          >
            {todo.title} - {todo.completed ? "Completed" : "Pending"}
          </li>
        ))}
      </ul>
      <div className="pages">
        <button disabled>Previous page</button>
        <span>Page 0</span>
        <button disabled>Next page</button>
      </div>
      <hr />
    </>
  );
}

This is how it should look once mounted. (I’ve also added some styles in CSS file)

Capture.PNG

Next, the two most important things are,

  • Query Client
    • It is responsible for managing queries and cache
  • Query Provider
    • Query Provider is responsible for caching the data and it provides client config to all the children.
    • It takes query client as the value which we will be creating next and connecting our App.js with Query Provider.

Let’s go ahead and import QueryClient and QueryClientProvider from react-query and implement it in the App.js file as we need to do this in the root component.

We create an instance of QueryClient using

const queryClient = new QueryClient();

and then we pass this instance to QueryClientProvider via props, which is wrapping everything that we are returning in App.js so all children can access client config and cache.

import "./styles.css";
import Todos from "./Todos";
import { QueryClient, QueryClientProvider } from "react-query";

const queryClient = new QueryClient();

export default function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <div className="App">
        <h1>Todo List</h1>
        <Todos />
      </div>
    </QueryClientProvider>
  );
}

This is how your App.js should look like.

Now, Its time to talk about Queries and useQuery Hook.

What is a Query and useQuery hook ?

According to the docs,

A query is a declarative dependency on an asynchronous source of data that is tied to a unique key.

and useQuery hook takes a unique key for the query and a function that returns a promise to fetch data from a server. The query results returned by useQuery contains all of the information about the query that your component needs.

Alright, enough talking. Let’s head to Todos.js component and create an async function above our Todos component that fetches a list of todos from JSON placeholder API in the same file.

const fetchAllTodos = async () => {
  const res = await fetch("https://jsonplaceholder.typicode.com/todos");
  return res.json();
};

Now, to implement useQuery hook, we need to import it as follow,

import { useQuery } from "react-query";

and then replace,

const data = [{ userId: 1, title: "Buy groceries", id: 1, completed: false }];

with

const { data, isError, error, isLoading } = useQuery(
    "todos",
    fetchAllTodos
  );

Let’s understand what’s happening in the above code snippet.

useQuery takes 3 arguments, first one is the query key and the second one is the function that returns a promise and the last one is a config object which provides additional info to useQuery hook on how to handle the query. We will dive into the third argument in another article as its optional so we are good with the first two arguments for now. We are further destructuring data, isError, error, isLoading from useQuery hook. It has a lot more things which you can destructure and use which we will be discussing later.

  • data: This is what you have fetched from API. In our case list of todos.
  • isError: This is a boolean(true/false) which turns true if there is any error while fetching the data from the API.
  • error: This has the error details about what went wrong.
  • isLoading: This is a boolean which turns true when we have no cache to read from and currently fetching the data from API.

With all these things combined we can structure our Todos component in the following way,


import React from "react";
import { useQuery } from "react-query";
const fetchAllTodos = async () => {
  const res = await fetch("https://jsonplaceholder.typicode.com/todos");
  return res.json();
};

export default function Todos() {
  const { data, isError, error, isLoading } = useQuery("todos", fetchAllTodos);
  if (isLoading) {
    return <h3>Loading</h3>;
  }
  if (isError) {
    return <h3>Oops, Something went wrong {error.toString()}</h3>;
  }
  return (
    <>
      <ul style={{ listStyle: "none" }}>
        {data?.map((todo) => (
          <li
            key={todo.id}
            style={{ color: todo.completed ? "green" : "orange" }}
            className="todo-title"
          >
            {todo.title} - {todo.completed ? "Completed" : "Pending"}
          </li>
        ))}
      </ul>
      <div className="pages">
        <button disabled>Previous page</button>
        <span>Page 0</span>
        <button disabled>Next page</button>
      </div>
      <hr />
    </>
  );
}

Here’s the final code of what we built in this article.

That’s it! You did it. I know sometimes it’s difficult to wrap your head around these concepts but react-query is a powerful tool that can help you maintain the server’s state on the frontend easily with caching.

We will be discussing more on other topics like pagination with react-query, query invalidations, mutations, prefetching, devtools in depth later in other articles. So stay tuned.


Tags

reactjsreact-querystate-management
Next Article
Introduction to Web Architecture
Sai Kranthi

Sai Kranthi

Software Engineer

Topics

React
Architecture
© 2021, All Rights Reserved.

Quick Links

Advertise with usAbout UsContact Us

Social Media