In the Global state management chapter, we have successfully implemented the cart page feature and parallel fetching of the cart products. In this lesson, we will learn how we can use react query for parallel fetching.
While the useQuery
hook is excellent for managing the state of a single query, it may not be sufficient when we need to handle multiple API requests concurrently. Additionally, we cannot use useQuery
hook inside a loop to send multiple API requests, as it violates the rules of hooks.
To address this, React query provides a hook called useQueries
. This hook allows us to fetch and manage the state of multiple queries simultaneously. It takes an array of query configuration objects and returns an array of results. Each query configuration object represents a separate API request.
Here's how you can use the useQueries
hook.
Consider an example, where we want to simultaneously fetch data for two products with slugs mens-cotton-jacket
and mens-casual-slim-fit
.
Similar to the useQuery
hook, this hook also supports specifying the queryKey
and queryFn
options for each query configuration object.
We can map over slugs to generate the configuration objects for each slug and then use the resulting array as the argument of the useQueries
hook.
We can use QUERY_KEYS.PRODUCTS
and slug
as the queryKey
to uniquely identify each configuration object. The queryFn
option will call the productsApi.show
method, which is responsible for fetching the product data for each slug
.
The useQueries
hook sends API requests to fetch both products in parallel and retrieve an array of query result objects. Each object contains properties such as data
, isLoading
, isFetching
etc.
Define a hook to fetch cart products
Inside the useProductsApi.js
file, we will define a hook called useFetchCartProducts
which takes a single parameter slugs
. Within this hook, we will call the useQueries
hook.
As we know, useQueries
hook returns an array of query result objects. We will extract the data
property from each response object. If the data
property is undefined
or null
due to the corresponding query not being resolved or if there was an error fetching the data, we will filter out such objects from the resulting array.
We need to check whether any of the requests are still in progress. To achieve this, we will examine whether any object in the responses array has an isLoading
property set to true
. We can make use of the existsBy function from neetocist
. It returns true if the array contains an item that matches the provided pattern.
Within the fetchCartProducts
function in the Cart/index.jsx
file, we have already added the logic to verify and update the cart items store if the quantity of a specific item in the cart exceeds its current stock, as shown below.
We will incorporate this same logic within the onSuccess
callback of the useQueries
option. This callback will be invoked upon the successful API call, and it will receive the fetched data as an argument.
We will now update the existing logic related to fetching product details through parallel queries in the Cart/index.jsx
file by replacing the useEffect
, fetchCartProducts
, and useState
with the useFetchCartProducts
hook, passing slugs
as an argument. Also, we will replace the existing usage of useCartItemsStore
to extract only slugs
from the store.
To improve readability, we will alias the data
property returned by the useFetchCartProducts
hook to products
. We will also set its default value to an empty array.
Let's commit the new changes:
You can verify the changes here.