DEV Community

Cover image for What is react-query? Why should we use react-query?
chauhoangminhnguyen
chauhoangminhnguyen

Posted on • Edited on • Originally published at howtodevez.blogspot.com

What is react-query? Why should we use react-query?

Introduction 📯📯📯

You might have heard or seen others mention the react-query library quite often. Why should we use react-query when we can use useEffect to fetch data from an API? This article will answer that question.

What is react-query? 🌱🌱🌱

react-query is a set of hooks for fetching, caching, and updating asynchronous data in React.

Simply put, react-query is a library for fetching, caching, and updating asynchronous data when used in React.

Why should we use react-query? 🌱🌱🌱

Normally, there are many ways to fetch data from a server. Some popular methods include using useEffect and useState, or using a state management library like redux.

export const Page = () => {
  const [data, setData] = useState();
    useEffect(() => {
      const loadData = async () => {
        const response = await fetch(hostAPI).then(response => response.json());
        setData(response)
    }
    loadData()
  })
  return <DisplayData />
}
Enter fullscreen mode Exit fullscreen mode

This method works fine, but it’s quite cumbersome. You have to write a bunch of code just to fetch data from the server and display it to the user. This method has the advantage of being simple to use, easy to read, and easy to understand. However, in cases where complex processing is required, such as caching response data, you need to implement a lot more. Luckily, react-query will support us in these cases.

Using react-query 🌱🌱🌱

react-query provides simple hooks to fetch and update data from the server. It supports caching, re-fetching, and much more.

First, let’s learn how to fetch data using useQuery.

useQuery ⭐⭐

To use the useQuery hook, you must pass at least two parameters:

The first parameter is the query key, which is a string[] data type, used for re-fetching, caching, and sharing data between components.
The second parameter is a function typically used to call an API, which returns a promise used to resolve data or throw an error.
The third parameter is the options (optional) that useQuery supports.
useQuery returns necessary information such as data, isFetching, or isError. We then use this information to display appropriate information.

Here’s an example:

import {useQuery} from '@tanstack/react-query'

const Page = () => {
  const { data, isFetching, isError } = await useQuery(['todo'], () => fetch(hostAPI).then(response => response.json()))
  if (isFetching) {
    return <Loading />
  }
  if (isError) {
    return <Error />
  }
  return <DisplayData />
}
Enter fullscreen mode Exit fullscreen mode

useMutation ⭐⭐

useMutation is used to create/update/delete data. This hook includes the following parameters:

The first parameter is the mutation key (similar to the query key).
The second parameter is a function that returns a promise to resolve data or throw an error.
The third parameter is the options.
The result returned by the useMutation hook is isFetching, isError, data similar to useQuery, in which there is an additional mutate function used to pass params when calling the API to create/update data.

Here's how to use it:

import {useMutation} from '@tanstack/react-query'

export const addProduct = (product: Partial<Product>): Promise<Product> =>
  fetch(`${hostAPI}/add`, {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify(product),
  })
  .then(res => res.json())
  .catch(() => {
    throw new Error('Failed addProduct')
  })

function Page() {
  const {mutate, isError, isFetching, data} = useMutation(['add-product'], addProduct)
  return (
    <div>
      <button onClick={() => mutate({id: 1, title: 'title 1'})}>
        Add product
      </button>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Example of use with option param 🍬🍬🍬

Pre-fetching data ⭐⭐

In case you have a list of articles belonging to a series on a certain topic, you would want the system to automatically fetch data of the next article when the user clicks on any article. We can use react-query to implement this feature as follows:

import {useQuery, useQueryClient} from '@tanstack/react-query'

export default function Index() {
  const [id, setId] = useState<number>(1)
  const queryClient = useQueryClient()
  const {data, error, isFetching} = useQuery(['list-post', id], () => getPostDetail(id), {
    onSuccess: () => {
      const nextID = id + 1
      // prefetch data, next time must request this queryKey it will use the cache data
      queryClient.prefetchQuery(['list-post', nextID], () => getPostDetail(nextID))
    },
    onError: console.error, // log error
  })
  return <DisplayData />
}
Enter fullscreen mode Exit fullscreen mode

Here, the option object takes in two functions: onSuccess and onError:

  • onSuccess runs when the query is executed successfully. I use the method queryClient.prefetchQuery (useQueryClient) to prefetch the data of the next post. If the user accesses any post, the data of the next post will be fetched in advance so that it can be used immediately when the user accesses that post.
  • onError runs if the query encounters an error.

Optimistic UI updates ⭐⭐

This is the case when we want to update the UI before receiving the response data result (and will update the accurate data later).

For example, when clicking like, the UI will render as liked during the API call process. After getting the response data, the UI will be updated according to the corresponding status. This way, the user won't have to wait too long for this function (helping to enhance the user experience).

export default function Page() {
  const [isLike, setLike] = useState<boolean>(false)
  const {mutate} = useMutation(['change-status'], updateLike, {
    onMutate: () => setLike(true), // set status while waiting reponse
    onSuccess: setLike, // set status after receiving response data
    onError: console.error,
  })
  return isLike
}2
Enter fullscreen mode Exit fullscreen mode
  • useMutate runs before a mutation is successful or encounters an error. At this point, we’ll make preliminary changes to the state here.
  • onSuccess runs after the mutation has been executed (regardless of success or error). At this point, we’ll update the state depending on the response data.

Conclusion 🏆🏆

React-query is a library that readily supports many features related to data requests, caching, and more. It also has many other great features that you can check out in more detail here.

Don't hesitate to leave your thoughts in the comments section, and remember to like, share, and follow for more insightful content in the future!

If you found this content helpful, please visit the original article on my blog to support the author and explore more interesting content.🙏🙏

BlogspotDev.toFacebookX


Some series you might find interesting:

Top comments (2)

Collapse
 
rgolawski profile image
Rafał Goławski

Well said, this topic has been also well covered here: tkdodo.eu/blog/why-you-want-react-.... I highly recommend checking it out!

Collapse
 
cookiemonsterdev profile image
Mykhailo Toporkov 🇺🇦

From my experience it is really a good library, however it also not something that justified to use in big apps.
For example in nextjs, ssr is present so we do not need to relay on client fetching the same goes for server actions. In Remix there is loader feature to also load data on page loading and other logic can be handled with native js and react features.
For now, I really do not see advantages to include it to bundle...

Nevertheless, pretty good explanation of lib usage.