DRY Patterns for API Calls in React

Vishal Sharma
5 min readNov 5, 2021

--

In most of the React projects, we have components where we need to fetch the data from an API on the mount. React provides us with lifecycle methods, and hooks to accomplish that but usually, we end up duplicating the same code for handling the API call states in all of those components. In this article, we will talk about how can we avoid that by following DRY code principles using different React constructs.

The Problem

Each API call in an application has three states:

  • Loading — When the call is made.
  • Successful — When the API returns a successful response.
  • Error — When the call fails.

Let’s imagine that we are creating a very basic e-commerce application that has a Catalog page that shows the list of products available and a Cart page that shows the products added to the cart by the user. Both of these pages need to fetch the data from an API on the mount.

Let's get started by creating the API calls to fetch the products and the cart.

Service calls for getting the products and Cart

Using Class-Based Components

React class-based components give a lifecycle method named componentDidMount to execute the code only once after the initial render. This makes the method best suited for API calls on the mount.

Using the same method, we can create the Catalog and Cart Components as:

Catalog Component using React class component
Cart Component using React class component

Using Functional Components

React@16.8 came up with the concept of useState a hook using which we can maintain the state in functional components as well. Similar to componentDidMount , useEffect hook with empty dependencies array can be used to make an API call only once after the initial render.

Thus by using the functional components, we can create the Catalog and Cart Components as:

Catalog Component using React functional component
Cart Component using React functional component

More information about react hooks can be found here.

No matter if you are using the class-based components or functional components, we can see a lot of code duplication.

  • Both components have duplicated states to handle the API call state.
  • componentDidMount or useEffect hooks have the same code to fetch the data in both the components.
  • Both components have duplicated code in the render method to show the user experience depending upon the API state.

Solution

Refactoring using Higher Order Components

The concept of Higher order components is taken from Higher order functions in functional programming. The difference is, that instead of taking a function as an argument and returning a function, it takes a react component as an argument and returns another react component.

Using the concept, we can create a HOC named withApiCallOnMount which can take the component needed to make the API call on the mount and the service as arguments and return a component with the updated API states as props.

withApiCallOnMount Higher order component

To use the HOC, Catalog and Cart component will change as:

Catalog component using withApiCallOnMount HOC
Cart component using withApiCallOnMount HOC

If we notice, both the components are changed to stateless functional components now as the state logic is moved to a single HOC.

More information about HOCs can be found here

Refactoring using Custom Hooks

We can use the concept of React hooks to create custom hooks to extract the common code. A custom hook can use the predefined hooks and thus the consumer component can directly use the custom hooks instead of repeating the predefined hooks.

Using the concept, we can create a custom hook named useApiCallOnMount which will take service as an argument and return the API states to the consumer component.

useApiCallOnMount custom hook

To use the custom hook, the Catalog and Cart component will change as:

Catalog component using useApiCallOnMount custom hook
Cart component using useApiCallOnMount custom hook

More information about custom hooks can be found here.

In both the above two refactorings using HOC and Custom hook, we have also solved the problem of contradicting states. More information about the same can be found here.

ApiStateHandler as a reusable component

The last thing we need to worry about is the duplicated code in the render method. We are writing the same stuff in both the components to return the JSX according to the API state.

To resolve this, we can create another react component, which takes the API states as props and render the appropriate JSX according to the passed prop.

ApiStateHandler component for extracting common rendering code

To use the ApiStateHandler component, Catalog and Cart components will change as:

Catalog component using ApiStateHandler component
Cart component using ApiStateHandler component

In the end, if your application needs more than a simple solution to fetch and update but even caching the response and many more, you can always try the well-known libraries React Query or SWR as one in all solutions for you.

A lot more patterns of refactoring a react app can be found in this Github repo.

--

--