ReactHustle

How to call REST api using Hooks in React

Jasser Mark Arioste

Jasser Mark Arioste

How to call REST api using Hooks in React

This tutorial shows us different ways of calling REST API correctly in React by using react hooks. We also explore the choices involved in what library to use in different scenarios when managing server state. One scenario is when a component loads and another one is after a certain action. We'll start with the most basic usage and then make our way up to using libraries to make our life easier. Let's learn some basics first.

What is server state in React? #

Server state is the state/data stored on the server (i.e.,  orders, users, settings), we use it to display data to the user and cache it on the client for performance reasons. Basically, anything that has to do with backend data is server state. So when calling an API, the data returned by the server is server state.

What NOT to do when calling APIs #

Let's start by showing what not to do when calling APIs in a Functional Component. At first thought you might be tempted to call fetch directly in a react functional component. And let's say after calling the api we update some state of our component


import * as React from 'react';

export default function App() {
  const [count, setCount] = React.useState(0);
  fetch('https://jsonplaceholder.typicode.com/users').then(() => {
    setCount(count + 1);
  });
  return (
    <div>      
      <p>API called {count} times</p>
    </div>
  );
}

1234567891011121314

In the example above, it increments the count by one after calling a fake API. However we quickly realize that this results in an infinite loop. Once we set the state, it triggers a re-render of the component, which triggers another call to the api, which triggers another increment to the state, and then another re-render.

Result from updating the count

To do this properly in the most basic way, we have to use useEffect hook. Let's explore how to do that in the next section.

Using useEffect to call an API #

Let's modify our code a bit and wrap our fetch call inside a useEffect hook.

import * as React from 'react';

export default function App() {
  ...

  React.useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/users').then(() => {
      setCount(count + 1);
    });
  }, []);

  ...
}
12345678910111213

Now it is fixed and only calls the API once.

Result after wrapping fetch inside useEffect.

What does useEffect do? Let's check it right from the react docs!

By using this Hook, you tell React that your component needs to do something after render. React will remember the function you passed (we’ll refer to it as our “effect”), and call it later after performing the DOM updates. In this effect, we set the document title, but we could also perform data fetching or call some other imperative API.
- https://reactjs.org/docs/hooks-effect.html

What are the disadvantages of using useEffect?

One problem of using useEffect for api calls is that you have to manually track the data, loading and error states. You'll have to do this for all endpoints.

useEffect is fine for small apps or when you are still learning BUT sooner or later when your building real-world applications, you'll face problems like caching, deduplication, and so on. And for these problems we'll need more specialized solutions in dealing with server state.

Using useFetch to call an API #

In this section we'll use a more improved version of useEffect. We'll be using useFetch from use-hooks or usehooks-ts libraries.

What features does useFetch provide us?

It provides us with the following features:

  1. Fetching data 
  2. Caching - either by memory or localStorage
  3. Automatically takes care of data and error states.

How to use useFetch in React

First let's install usehook-ts (if you're using typescript) or usehooks

yarn add usehooks-ts
1

Let's modify our component to use useFetch:

import React, { memo } from "react";
import { useFetch } from "usehooks-ts";

const Users = () => {
  const { data, error } = useFetch(`https://jsonplaceholder.typicode.com/users`);

  return (
    <div>
      <pre>{JSON.stringify(data, null, 4)}</pre>
      {!!error && <div>{error?.message}</div>}
    </div>
  );
};

export default memo(Users);
123456789101112131415

Using useFetch allows us to have a more descriptive api for our component and it handles the data and error states for us. 

Should you use useFetch in real-world apps?

Although it is an improvement from useEffect, it's still insufficient for real-world applications. It also doesn't support SSR which is mandatory to have optimized SEO. The docs also recommends using other libraries like react-query or swr.

In the next section we'll move to using production-grade solutions for fetching server data in react.

Using useSWR to call an API in React #

SWR is a great solution for data fetching in react. The name “SWR” is derived from stale-while-revalidate, a HTTP cache invalidation strategy popularized by HTTP RFC 5861. It gives us more powerful features that the first two solutions didn't provide.

What are the features of SWR?

Below are the features of swr directly from their website:

  • Fast, lightweight and reusable data fetching
  • Built-in cache and request deduplication
  • Real-time experience
  • Transport and protocol agnostic
  • SSR / ISR / SSG support
  • TypeScript ready
  • React Native
  • Revalidation on focus
  • Fast page navigation
  • Polling on interval
  • and many more

How to use useSWR in react

The usage is identical to useFetch, so if you use useFetch you can easily swap swr for more features.

Lets install swr:

yarn add swr





1

Modify our component to use the  useSWR hook:

import React, { memo } from "react";
import useSWR from "swr";

//let's define a fetcher function that uses the fetch api
const fetcher = (url: string) => fetch(url).then((res) => res.json());

const Users = () => {
  const { data, error } = useSWR(`/users?page=0&size=10`, fetcher);

  return (
    <div>
      {data ? (
        <pre>{JSON.stringify(data, null, 4)}</pre>
      ) : (
        <div> loading... </div>
      )}

      {!!error && <div>{error?.message}</div>}
    </div>
  );
};

export default memo(Users);


export default memo(Users);
1234567891011121314151617181920212223242526

The nice thing about defining fetcher function to fetch the data is that the implementation is not tightly coupled to the swr library. This is unlike useFetch which only uses fetch api from the browser. In swr, we can use any library we want like such as axios, or grahpql-request (for graphql queries) or  just the native fetch api from the browser.

Should you use SWR for production-grade apps?

You should definitely consider using swr in production-grade applications. The features and flexibility it provides are more than enough reason to use this awesome data-fetching library.

The above example doesn't do swr justice, we haven't scratched the surface of how awesome this library is in terms of data-fetching in react. However, this tutorial will not dive-deep into swr as I think it deserves its own post.

Using useQuery to call an API #

useQuery is the react hook from a more famous data-fetching library react-query. Let's dive into it!

What are the features of react-query?

Based on npm documentation, below are the features:

  • Transport/protocol/backend agnostic data fetching (REST, GraphQL, promises)
  • Auto Caching + Refetching (stale-while-revalidate, Window Refocus, Polling/Realtime)
  • Parallel + Dependent Queries
  • Mutations + Reactive Query Refetching
  • Multi-layer Cache + Automatic Garbage Collection
  • Paginated + Cursor-based Queries
  • Load-More + Infinite Scroll Queries w/ Scroll Recovery
  • Request Cancellation
  • React Suspense + Fetch-As-You-Render Query Prefetching
  • Dedicated Devtools
  • 13kb minizipped size

It's pretty much similar to swr in terms of features.

How to use useQuery in react

Usage is pretty similar to swr. But first let's install it!

yarn add @tanstack/react-query
1

Let's setup the queryClient and QueryClientProvider in a top-level component like _app.tsx


import type { AppProps } from "next/app";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
//create a query client
const queryClient = new QueryClient();

function App({ Component, pageProps }: AppProps) {
  return (
    <QueryClientProvider client={queryClient}>
      <Component {...pageProps} />;
    </QueryClientProvider>
  );
}

export default App;
123456789101112131415

Let's modify our code above to use react-query:


import React from "react";
import { useQuery } from "@tanstack/react-query";

//let's define a fetcher function that uses the fetch api
const fetcher = () => fetch(`/users?page=0&size=10`).then((res) => res.json());

interface User {
  id: number;
  firstName: string;
  lastName: string;
  maidenName: string;
  age: number;
  gender: string;
  email: string;
}

const Users = () => {
  // we can use generics for the useQuery hook to indicate
  // the data type and error type
  const { data, error } = useQuery<User[], Error>([`users`], fetcher);

  return (
    <div>
      {data ? (
        <pre>{JSON.stringify(data, null, 4)}</pre>
      ) : (
        <div> loading... </div>
      )}

      {!!error && <div>{error.message}</div>}
    </div>
  );
};

export default Users;

123456789101112131415161718192021222324252627282930313233343536

Not using a queryClient will throw a runtime error

Error:No QueryClient set, use QueryClientProvider to set one

Should you use react-query for production grade apps?

react-query should definitely be on the top of the list when considering which library to use for server state management in react. 

Conclusion #

We learned how to call rest api by using hooks in react. We started from the very basics, we considered our options and use libraries as we progressed to give us more features for handling server state. We didn't tackle too much on libraries  like swr and react-query since it's outside the scope of this tutorial and I believe they deserver their own post.

I wanted to write this tutorial for beginners and I wanted to give a glimpse on what's being used in production just to broaded the scope of your knowledge. 

Thank you for reading! Hopefully you enjoyed this tutorial. If you enjoyed, kindly leave a like or even share. If you like tutorials like these, please subscribe to our newsletter down below!

Resources #


Credits: Image by Jan Alexander from Pixabay

Share this post!

Related Posts

Disclaimer

This content may contain links to products, software and services. Please assume all such links are affiliate links which may result in my earning commissions and fees.
As an Amazon Associate, I earn from qualifying purchases. This means that whenever you buy a product on Amazon from a link on our site, we receive a small percentage of its price at no extra cost to you. This helps us continue to provide valuable content and reviews to you. Thank you for your support!
Donate to ReactHustle