This is Part-3. This blog post will explain how Data fetching using react query.
In case if you do not have any idea about the basics of React Query and how to start with it, you can refer to link
Quick links for our Part Series:
PART #1 - Introduction and Installation of ReactJS
PART #2 - ReactJS split the UI by components Components
PART #3 - React Query for remote data fetching instead of Redux thunk (This Post)
PART #4 - Internationalization with i18next
PART #5 - Basics to Advanced Usage of styled-components
Keep in mind that if you get stuck on any step, refer to the Github repo
To find the completed project, Demo link
Now, first things first. Why we need React Query instead of Redux and What is the pain point in Redux.
Although I have been using Redux to handle data fetching in many of my projects, I’ve always believed there must be a better way to do the same with React JS
Each fetch operation requires the developer to create:
- three actions (fetch request, succeeded, failed)
- three reducers (fetch request, succeeded, failed)
- one middleware (usually redux-saga or redux-thunk)
Writing all this code takes a lot of time, even for a simple API call. Moreover, it’s not hard to end up with a big JS bundle.
Overview of Redux store
Every fetch operation performed by Redux has to save its loading and response statuses in the Redux store. Yet, most of the time, the component performing that operation doesn’t need to share its data with other components. Consequently, there is no need to store it in the Redux Store.
Let’s review a typical Redux Flow
It’s a long process for just a simple fetch, isn’t it?
I would like to take a step back end to rethink the whole thing from a high-level perspective, not including Redux. The basic idea is:
- Let’s perform the fetch op from the Component and wait for the response
- Once we get the response, we update the local state of the Component
- Optionally, if we need to save the response (or part of it) in the Redux store, we can do so by dispatching a dedicated Action
Thanks to React Hooks, we can abstract the fetch operation into a custom and reusable useFetch hook
import axios from "axios";
import toast from "react-hot-toast";
import ErrorHandleResponses from "../../api-repositories/error-handler";
const REACT_APP_DUMMY_API_ENDPOINT = "https://dummyapi.io/data/api/";
axios.defaults.headers["app-id"] = "lTE5abbDxdjGplutvTuc";
export const getAuthors = async () => {
try {
const url = `${REACT_APP_DUMMY_API_ENDPOINT}user?limit=30`;
const { data } = await axios.get(url);
return data || [];
} catch (err) {
const errorCode = ErrorHandleResponses(err.response);
if (errorCode.error) {
toast.error(`${errorCode.error} Http Error code`);
}
return errorCode;
}
};
export const getAuthorPosts = async (userId) => {
const { data } = await axios.get(
`${REACT_APP_DUMMY_API_ENDPOINT}user/${userId}/post?limit=10`
);
return data;
};
export const getAuthorDetail = async (userId) => {
const { data } = await axios.get(
`${REACT_APP_DUMMY_API_ENDPOINT}user/${userId}/`
);
return data;
};
With this approach, we don’t need to store any information about the fetch operation in Redux. If there is any need to share it, we can store the final result (or part of it ) anyway.
import React, { useEffect, lazy } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useAuthors } from './authors-hooks';
import { authorSelector, authorsReceived } from './author-slice';
const AuthorListing = () => {
const { authors, filters: authorFilter } = useSelector(authorSelector);
const dispatch = useDispatch();
const { data, isFetching } = useAuthors();
const renderStatus = data && data.data;
useEffect(() => {
if (renderStatus) {
dispatch(authorsReceived(data.data));
}
}, [renderStatus]);
};
AuthorListing.displayName = 'AuthorsListing';
export default AuthorListing;
This solution is simpler, but obviously not good enough. There is no separation of concerns, there will be a lot of code duplication, verbose logic within the component, etc.
Simple and clean, thanks to the “magic” of Hooks and React Query.
React Query makes fetching, caching, synchronizing, and updating the server state in your React applications a breeze.
Tips & Tricks
Never use useQuery inside the Component. Instead, wrap it into a custom hook
To be continued Part-4
Top comments (0)