How to manage API calls in React

The React library is known for building rich and highly scalable user interfaces. There are many ways to fetch data from an external API in React.

Before you go through this Answer, it’s a good idea to make yourself familiar with the React library and Application Programming Interface (API).

In this Answer, we will discuss different ways to manage API calls in React. In the end, you will be able to choose the best approach based on the application requirements.

1. The Fetch API

Fetch API is built into most modern browsers on the window object (window.fetch), and enables us to easily make HTTP requests.

The following code snippets show a simple example of Fetch API in practice:

import {useEffect} from "react";

const fetchUsers = () => {
// Where we're fetching data from
return fetch("http://www.abc.cd/test")
// We get the API response and receive data in JSON format
  .then((response) => response.json())
  .then((data) => console.log(data))
  .catch ((error) => console.error(error));}

The only goal of this function is to access the data and convert the response into JSON using the response.json() method. Here, the JSON() method is used to get the response object stored in the data and update the users’ state in our application.

Fetch is promise-based, which means we can also catch errors using the .catch() method. Any encountered error is used as a value to update our error’s state.

Now, adding to that, we will make this request, within the useEffect() hook, with an empty dependencies array as the second argument. This is done so that our request is only made once and is not dependent on any other data.

Here is an example how to use it in the useEffect() hook:

import {useEffect} from "react";

useEffect(() => {
    fetchData()
  }, []);

Isn’t this handy? Let’s see what the other methods do.

2. Axios library

Axios is a Promise-based HTTP client for JavaScript that can be used in your front-end application and Node.js backend.

When using Axios, it’s easy to send asynchronous HTTP requests to REST endpoints and perform CRUD operations.

In this example, we first have to install Axios using npm or yarn. Then, we will add it as an import to our parent component.

npm install axios

The following code snippets show an example of how to use Axios:

import axios from "axios"

const fetchData = () => {
return axios.get("http://www.abc.cd/test")
   .then((response) => console.log(response.data));
}

Similar to the Fetch API, Axios also returns a promise. However, in Axios, it always returns a JSON response. The coding part is similar to the Fetch API, except that it has shorter steps and better error handling.

3. async/await syntax

async/await is a relatively new way to synchronously write asynchronous code.

When the async keyword is place before a function, it has two effects:

  • Makes it always return a promise.
  • Allows await to be used within it.

The await keyword before a promise makes JavaScript wait until that promise settles, and then:

  • If it’s an error, the exception is generated.
  • Otherwise, it returns the result.

Take a look at the following code snippets:

async function fetchData() {
    try {
      const result = await axios.get("http://www.abc.cd/test")
      console.log(result.data));
    } catch (error) {
      console.error(error);
    }
  }

When we use useEffect(), the effect functionthe first argument cannot be made an async function. For that, we can create a separate async function in our component that we can synchronously call within useEffect and fetch our data accordingly.

5. React-query library

React-query is a great library that solves the problem of managing server state and caching in applications.

"It makes fetching, caching, synchronizing, and updating server state in your React applications a breeze.”

Firstly, let’s install the required package:

npm install react-query react-query-devtools

Note: React-query also has its own dev tools that help us to visualize the inner workings of React-query.

React-query gives us a cache that you can see below through the React Query Devtools. This cache enables us to easily manage the requests we have made according to the key-value we specify for each request.

import React from "react";
import ReactDOM from "react-dom";
import { QueryClient, QueryClientProvider, useQuery } from "react-query";
import { ReactQueryDevtools } from "react-query/devtools";

const queryClient = new QueryClient();

export default function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <FetchData />
    </QueryClientProvider>
  );
}

function FetchData() {
  const { data } = useQuery("UserData", () =>
    fetch("http://www.abc.cd/test").then((res) => res.json())
  );

  return (
    <div>
       // data you want to show
      <ReactQueryDevtools initialIsOpen />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

In short, we need to tell the library where we need to fetch the data and it will handle caching, background updates, and refresh data without any extra code or configuration.

It also provides some hooks or events for mutation, queries to handle errors, and other states of side effects that remove the need for useState() and useEffect() hooks and replaces them with a few lines of React-query logic.

There are various other ways to manage data fetching, such as SWR and GraphQL API, but this Answer does not explain them in-depth.

That’s about it!

Happy coding, and thank you for reading.

Copyright ©2024 Educative, Inc. All rights reserved