React Hustle

How to use Axios in NextJS using axios-hooks Package

JA

Jasser Mark Arioste

How to use Axios in NextJS using axios-hooks Package

Hello, hustler! In this tutorial, you’ll learn how to use axios on the client-side in NextJS using the axios-hooks package. We’ll also use typescript throughout the tutorial.

Introduction

In every production web app, we always need some kind of HTTP client to handle requests and axios is a really good HTTP client with a lot of features.

I checked the currently available axios hooks libraries such as axios-hooks and use-axios-client . I found out that axios-hooks has a really good implementation for React. One problem I found is that it’s a bit tricky to set up SSR with NextJS since it has an opinionated way of setting up SSR. Also, most of its examples of SSR are also done using express.

In this tutorial, you’ll learn how to install and use axios-hooks and set up SSR with it in NextJS.

Installing the Dependencies

First, let’s install axios and axios-hooks package by running the command:

yarn add axios axios-hooks

Now, we’re ready to make some requests on the browser.

How to do a GET Request

To call a GET request, all we have to do is to use the useAxios hook. We can pass an AxiosRequestConfig object to customize the request:

// pages/users.tsx
import useAxios from "axios-hooks";
// define UserResponse for type-safty
type User = {
  id: string;
  firstName: string;
  age: number;
};

interface UserResponse {
  users: User[];
  total: number;
  skip: number;
  limit: number;
}

const UsersPage = () => {
  //use the useAxios hook and pass the AxiosRequestConfig
  const [{ data, loading, error }] = useAxios<UserResponse>({
    baseURL: "https://dummyjson.com",
    url: "/users?skip=0&limit=5&select=firstName,age",
  });

  return (
    <div>
      <h1>Users Page</h1>
      {loading && <p>Loading...</p>}
      {!!error && <p>{error.message}</p>}
      {!!data && <pre>{JSON.stringify(data, null, 4)}</pre>}
    </div>
  );
};
export default UsersPage;

It uses the useEffect hook internally to call the request once the component is rendered and gives us the loading , error and data states.

If you want to delay or have more control over the timing of the call, you can use the {manual:true} option:

// pages/users.tsx
const UsersPage = () => {
  //useAxios returns a 2nd element to refetch the array
  const [{ data, loading, error }, refetch] = useAxios<UserResponse>(
    {
      baseURL: "https://dummyjson.com",
      url: "/users?skip=0&limit=5&select=firstName,age",
    },
    // use manual:true so that it doesn't run on the first render
    {
      manual: true,
    }
  );

  return (
    <div>
      <h1>Users Page</h1>
      <button onClick={() => refetch()}>Load Users</button>
      {loading && <p>Loading...</p>}
      {!!error && <p>{error.message}</p>}
      {!!data && <pre>{JSON.stringify(data, null, 4)}</pre>}
    </div>
  );
};

Here’s the output:

The { manual:true } option is especially useful if you’re using a POST/PUT request.

More information about this can be found in its documentation on GitHub: simoneb/axios-hooks

Implementing axios-hooks SSR for NextJS

I had some trouble implementing SSR for axios-hooks since there are currently no examples for NextJS. I was able to get around it by digging into the axios-hooks code. If you have the same problem as me, I think this will help you a ton.

How axios-hooks does SSR normally

The axios-hooks package does server-side rendering (SSR) by first rendering the app. As it renders the app, all the requests will be stored in an LRU cache. Next, it renders the cache contents using serializeCache . Then load the cache in the browser using the loadCache once it React hydrates the page.

The Problem in NextJS

The above method does not work In NextJS because we don’t have the opportunity to call React.hydrateRoot since this is done internally by NextJS. We don’t have a place to call serializeCache .

Solving the Problem

Here are the steps of how I solved this problem which turned out to be pretty simple:

  1. Create a cache data exactly the same as axios-hooks in getStaticProps or getServerSideProps
  2. Pass the cache data to the props
  3. use loadCache in _app.tsx

First, let’s create a serializeResponse function that mimics seralizeCache . Create the file lib/serializeResponse.ts

// lib/serializeResponse.ts
import { AxiosRequestConfig, AxiosResponse } from "axios";
// the cached item for axios hooks have this structure
type CacheItem = [string, { value: any }];

// use the config and the response to create a cached item
export function serializeResponse(
  config: AxiosRequestConfig,
  response: AxiosResponse<any, any>
): CacheItem {
  const key = JSON.stringify({ ...config });
  return [
    key,
    {
      value: {
        data: response.data,
        headers: {
          ...response.headers,
        },
        status: response.status,
        statusText: response.statusText,
      },
    },
  ];
}

Here, we’re just creating cached data similar to how axios-hooks does it.

Next, let’s use getServerSideProps to execute the request on the server and pass data to the client:

import axios, { AxiosRequestConfig } from "axios";
import useAxios from "axios-hooks";
import { GetStaticProps } from "next";
import { serializeResponse } from "../lib/serializeResponse";
// define UserResponse for type-safety
type User = {
  id: string;
  firstName: string;
  age: number;
};

interface UserResponse {
  users: User[];
  total: number;
  skip: number;
  limit: number;
}

const UsersPage = () => {
  //useAxios returns a 2nd element to refetch the array
  const [{ data, loading, error }, refetch] = useAxios<UserResponse>({
    baseURL: "https://dummyjson.com",
    url: "/users?skip=0&limit=5&select=firstName,age",
  });

  return (
    <div>
      <h1>Users Page</h1>
      <button onClick={() => refetch()}>Load Users</button>
      {loading && <p>Loading...</p>}
      {!!error && <p>{error.message}</p>}
      {!!data && <pre>{JSON.stringify(data, null, 4)}</pre>}
    </div>
  );
};
export default UsersPage;

export const getServerSideProps: GetStaticProps = async () => {
  // axios config, must be exactly the same as the one used in useAxios hook so that it creates the same key.
  const config: AxiosRequestConfig = {
    baseURL: "https://dummyjson.com",
    url: "/users?skip=0&limit=5&select=firstName,age",
  };
  // execute the http request
  const response = await axios(config);

  // serialize the response
  return {
    props: {
      __CACHE__: [serializeResponse(config, response)],
    },
  };
};

Lastly, on _app.tsx , we have to call loadCache .

// pages/_app.tsx
import "../styles/globals.css";
import type { AppProps } from "next/app";
import { loadCache } from "axios-hooks";
function MyApp({ Component, pageProps }: AppProps) {
  loadCache(pageProps.__CACHE__ ?? []);
  return <Component {...pageProps} />;
}
export default MyApp;

When we check the network tab, there are no calls to dummy JSON API on the client side:

How to do POST / PUT Request

To use POST/PUT request, you may pass the { method: "POST" } option and { manual: true} . For example, suppose we are implementing a signup page:

// pages/signup.tsx
import useAxios from "axios-hooks";
type SignUpResponse = {
  success: boolean;
};
const SignupPage = () => {
  const [{ data, loading, error }, signup] = useAxios<SignUpResponse>(
    {
      url: "/api/signup",
      method: "POST",
    },
    {
      manual: true,
    }
  );

  return (
    <div style={{ padding: 16 }}>
      <form
        onSubmit={(e) => {
          e.preventDefault();
          signup();
        }}
      >
        <h1>Sign Up</h1>
        <input name="username" />
        <input name="password" />
        {error && <p>{error.message}</p>}
        {data?.success && <p>Successfully signed up</p>}
        <div>
          <button>{loading ? "Loading..." : "Sign up"}</button>
        </div>
      </form>
    </div>
  );
};
export default SignupPage;

We use the second element returned by the <span>useAxios</span> hook to manually call the request on form submission. Then we use the error , data , and loading states to reflect the status of the request to the UI.

Full Code and Demo

The full code is available on GitHub: jmarioste/nextjs-axios-hooks-tutorial

The demo is available on Stackblitz: nextjs-axios-hooks-tutorial

Conclusion

We learned how to use axios with NextJS using the axios-hooks library with Typescript. We also learned how to work around its SSR limitations with NextJS. To be honest, I think there are better HTTP client libraries for NextJS like swr and react-query . For example, SWR has a much easier API for implementing SSR in NextJS (they have examples), it also caching feature similar to axios-hooks and it’s only 4kb in bundle size. When you use axios and axios-hooks , it adds up to 18kb in total.

If you like this tutorial, please leave a like or share this article. For future tutorials like this, please subscribe to our newsletter or follow me on Twitter .

Resources

  1. Axios-hooks Repo
  2. Axios Documentation

Credits: Image by Анатолий Стафичук 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