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-hooks1
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;123456789101112131415161718192021222324252627282930313233
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> ); };123456789101112131415161718192021222324
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, }, }, ]; }12345678910111213141516171819202122232425
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)], }, }; };1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
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;123456789
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;12345678910111213141516171819202122232425262728293031323334353637
We use the second element returned by the useAxios 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






