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
1
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
cache
data exactly the same as axios-hooks ingetStaticProps
orgetServerSideProps
- Pass the cache data to the props
- 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, }, }, ]; }
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