DEV Community

loading...
Cover image for React Project: HashTags for Posts with Auth — Part #3

React Project: HashTags for Posts with Auth — Part #3

selvaece25 profile image Selva kumar ・3 min read

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

Alt Text

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:

  1. Let’s perform the fetch op from the Component and wait for the response
  2. Once we get the response, we update the local state of the Component
  3. 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;
};

Enter fullscreen mode Exit fullscreen mode

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;

Enter fullscreen mode Exit fullscreen mode

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

Discussion (0)

Forem Open with the Forem app