How to use Axios in NextJS using axios-hooks Package
Jasser Mark Arioste
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:
- Create a
cachedata exactly the same as axios-hooks ingetStaticPropsorgetServerSideProps - Pass the cache data to the props
- use
loadCachein_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
Credits: Image by Анатолий Стафичук from Pixabay


