In the modern web development world, communicating with a server to fetch or send data is an essential part of any application. For React developers, there are many ways to do this, and Axios stands out as a popular, powerful, and flexible HTTP client library.
This article is a comprehensive guide, diving deep into every aspect of using Axios in React. Whether you're a beginner or an experienced developer, you'll find useful knowledge to optimize API calls in your projects.
What is Axios? Why use it in React?
Axios is a Promise-based HTTP client for the browser and Node.js. It provides an easy and logical way to fetch network resources and is a powerful and flexible alternative to the native Fetch API.
So why is Axios popular in React?
- Easy to use: Simple and clean API for making HTTP requests.
- Automatic JSON transformation: Axios automatically transforms request and response data to and from JSON.
- Better error handling: Axios automatically rejects promises for HTTP errors (4xx, 5xx), making error handling easier.
- Request cancellation: Supports request cancellation via
CancelToken
orAbortController
. - Interceptors: Allows you to intercept requests or responses before they are handled by
then
orcatch
. - Progress tracking: Supports upload and download progress tracking.
- Wide browser support: Works on most browsers without the need for polyfills.
Basic Operations with Axios in React
Let's start with the basics. We'll use the useState
and useEffect
hooks to perform a simple GET
request to fetch data and display it in the UI.
1. Performing a GET Request
This is the most common scenario: fetching data from an API and displaying it.
Scenario: We'll fetch a list of users from the public API JSONPlaceholder.
import React, { useState, useEffect } from 'react'
import axios from 'axios'
function UserList() {
const [users, setUsers] = useState([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
useEffect(() => {
const fetchUsers = async () => {
try {
const response = await axios.get(
'https://jsonplaceholder.typicode.com/users',
)
setUsers(response.data)
} catch (e) {
setError(e.message)
} finally {
setLoading(false)
}
}
fetchUsers()
}, [])
if (loading) return <div>Loading data...</div>
if (error) return <div>Error occurred: {error}</div>
return (
<div>
<h1>User List</h1>
<ul>
{users.map((user) => (
<li key={user.id}>
{user.name} - {user.email}
</li>
))}
</ul>
</div>
)
}
export default UserList
Code Analysis:
useState
: We use three states.users
to store data,loading
to track loading state, anderror
to catch any errors.useEffect
: This is where the API call logic lives. Placing it inuseEffect
ensures data fetching doesn't block UI rendering. The empty dependency array[]
means this effect runs only once, similar tocomponentDidMount
in class components.- Axios: Axios automatically transforms the response to JSON and throws errors for HTTP error status codes.
2. Sending Data with a POST Request
Now, let's see how to send data to the server, for example, creating a new post.
import React, { useState } from 'react'
import axios from 'axios'
function CreatePost() {
const [title, setTitle] = useState('')
const [body, setBody] = useState('')
const [message, setMessage] = useState('')
const handleSubmit = async (e) => {
e.preventDefault()
setMessage('Sending...')
try {
const response = await axios.post(
'https://jsonplaceholder.typicode.com/posts',
{
title: title,
body: body,
userId: 1,
},
)
setMessage(`Post created successfully with ID: ${response.data.id}`)
setTitle('')
setBody('')
} catch (error) {
setMessage(`Error: ${error.message}`)
}
}
return (
<form onSubmit={handleSubmit}>
<h2>Create New Post</h2>
<div>
<label>Title:</label>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
required
/>
</div>
<div>
<label>Body:</label>
<textarea
value={body}
onChange={(e) => setBody(e.target.value)}
required
/>
</div>
<button type="submit">Create</button>
{message && <p>{message}</p>}
</form>
)
}
Key points in the POST request:
- Axios automatically stringifies the data and sets the correct headers.
- Error handling is simpler because Axios throws for HTTP errors.
Advanced: Reusing Logic with a Custom Hook
As your app grows, you'll find yourself repeating useState
and useEffect
logic for API calls in many components. This is where Custom Hooks shine! We can encapsulate this logic into a reusable hook.
Let's create a versatile useAxios
hook.
// hooks/useAxios.js
import { useState, useEffect } from 'react'
import axios from 'axios'
function useAxios(config) {
const [data, setData] = useState(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
useEffect(() => {
const source = axios.CancelToken.source()
const fetchData = async () => {
setLoading(true)
setError(null)
try {
const response = await axios({ ...config, cancelToken: source.token })
setData(response.data)
} catch (e) {
if (!axios.isCancel(e)) {
setError(e.message)
}
} finally {
setLoading(false)
}
}
fetchData()
return () => {
source.cancel('Request canceled')
}
}, [JSON.stringify(config)])
return { data, loading, error }
}
export default useAxios
How to use the useAxios
Custom Hook:
Now, our UserList
component becomes much cleaner:
import React from 'react'
import useAxios from './hooks/useAxios'
function UserList() {
const {
data: users,
loading,
error,
} = useAxios({
method: 'get',
url: 'https://jsonplaceholder.typicode.com/users',
})
if (loading) return <div>Loading data...</div>
if (error) return <div>Error occurred: {error}</div>
return (
<div>
<h1>User List</h1>
<ul>
{users?.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
)
}
Why is this Custom Hook great?
- Reusable: You can use
useAxios
anywhere in your app. - Clean: Complex logic is abstracted away, letting your components focus on UI.
- Cancel handling: Prevents memory leaks when a component unmounts before the API call finishes.
Axios vs. Fetch API Comparison
Axios and Fetch API are both popular for HTTP requests. So, when should you choose Axios, and when Fetch?
Feature | Fetch API | Axios |
---|---|---|
Installation | Built-in | Needs to be installed via npm/yarn |
HTTP error handling | Does not auto-reject on HTTP errors | Auto-rejects promise on errors (4xx, 5xx) |
Data transformation | Manual .json() or .text() | Auto-converts to/from JSON |
Request cancellation | Supported via AbortController (verbose) | Supported via CancelToken or AbortController |
Upload/download progress | Not directly supported | Supported |
Old browser compatibility | Needs polyfill for IE | Works on most browsers |
Size | 0KB (built-in) | ~12KB (small, but still a dependency) |
From the comparison table:
- Choose Fetch API when: You want a dependency-free, lightweight solution and don't mind writing a bit more code for error handling and data transformation. Great for small projects or when you want full control.
- Choose Axios when: You need advanced features like auto JSON conversion, simpler HTTP error handling, interceptors, and upload progress support. Ideal for large and complex applications.
Conclusion: Axios is a Powerful Tool
Axios is a powerful and essential tool in a React developer's toolkit. By understanding how it works and combining it with React Hooks like useState
, useEffect
, and custom hooks, you can build efficient, clean, and maintainable React applications.
Hopefully, this comprehensive article has given you the insights and knowledge you need to confidently master API calls with Axios in your React projects.
Happy coding with React!