React
API Calls with Axios
Master HTTP requests with React's most popular API client - handle errors, loading states, and interceptors professionally.
Axios is like having a professional courier service for your API calls. While fetch is the basic mail service, Axios comes with package tracking, automatic retries, and premium features. Netflix uses it. So does Airbnb. You'll see why. The DataFlow team wants to upgrade from fetch to Axios. They need better error handling, request cancellation, and automatic JSON parsing. Time to make API calls feel effortless.Why Axios Over Fetch
Fetch requires manual work. Check response.ok, parse JSON, handle errors yourself. Axios does this automatically. Compare these approaches:// Fetch - manual everything
const fetchUsers = async () => {
try {
const response = await fetch('/api/users');
if (!response.ok) {
throw new Error('Network error');
}
const data = await response.json();
return data;
} catch (error) {
console.error('Fetch failed:', error);
}
};// Axios - automatic everything
import axios from 'axios';
const fetchUsers = async () => {
try {
const response = await axios.get('/api/users');
return response.data; // Already parsed JSON
} catch (error) {
console.error('Request failed:', error.response?.data);
}
};What just happened?
Axios automatically parsed JSON and gave us cleaner error objects. The response.data contains our actual data - no manual parsing needed. Try this: Install axios and watch your API calls become half the code.
Setting Up Axios
Install Axios first. Then create a configured instance. Think of it as your custom API client:// Install: npm install axios
// api.js - Central configuration
import axios from 'axios';
const api = axios.create({
baseURL: 'https://jsonplaceholder.typicode.com',
timeout: 5000,
headers: {
'Content-Type': 'application/json',
}
});
export default api;// UsersList.js - Using configured Axios
import React, { useState, useEffect } from 'react';
import api from './api';
function UsersList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchUsers = async () => {
try {
const response = await api.get('/users');
setUsers(response.data);
} catch (error) {
console.error('Failed to fetch users:', error);
} finally {
setLoading(false);
}
};
fetchUsers();
}, []);
if (loading) return <div>Loading users...</div>;
return (
<div>
<h2>DataFlow Users</h2>
{users.slice(0, 3).map(user => (
<div key={user.id} style={{padding: '12px', border: '1px solid #e2e8f0', margin: '8px 0'}}>
<strong>{user.name}</strong> - {user.email}
</div>
))}
</div>
);
}What just happened?
The configured Axios instance handled the API call automatically. Notice how response.data gave us the parsed JSON directly. Try this: Add error states and watch Axios catch network failures gracefully.
HTTP Methods with Axios
Axios makes every HTTP method feel natural. GET, POST, PUT, DELETE - all follow the same pattern. The DataFlow team needs CRUD operations for their analytics data:// All HTTP methods with Axios
import api from './api';
// GET - Read data
const getUsers = async () => {
const response = await api.get('/users');
return response.data;
};
// POST - Create new
const createUser = async (userData) => {
const response = await api.post('/users', userData);
return response.data;
};
// PUT - Update existing
const updateUser = async (id, userData) => {
const response = await api.put(`/users/${id}`, userData);
return response.data;
};
// DELETE - Remove
const deleteUser = async (id) => {
await api.delete(`/users/${id}`);
};// ReportForm.js - POST request with form data
import React, { useState } from 'react';
import api from './api';
function ReportForm() {
const [report, setReport] = useState({ title: '', metrics: '' });
const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
try {
await api.post('/reports', {
title: report.title,
metrics: report.metrics,
createdAt: new Date().toISOString()
});
setSuccess(true);
setReport({ title: '', metrics: '' });
} catch (error) {
console.error('Failed to create report:', error);
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleSubmit}>
<input
value={report.title}
onChange={e => setReport({...report, title: e.target.value})}
placeholder="Report title"
required
/>
<button type="submit" disabled={loading}>
{loading ? 'Creating...' : 'Create Report'}
</button>
{success && <div>Report created successfully!</div>}
</form>
);
}Error Handling and Loading States
Axios provides rich error information. Status codes, response data, request details. Use this for better user experience:// Advanced error handling with Axios
import React, { useState, useEffect } from 'react';
import api from './api';
function DataTable() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
setLoading(true);
setError(null);
const response = await api.get('/analytics');
setData(response.data);
} catch (err) {
if (err.response) {
// Server responded with error status
setError(`Server error: ${err.response.status}`);
} else if (err.request) {
// Network error
setError('Network error - check connection');
} else {
setError('Request failed');
}
} finally {
setLoading(false);
}
};
fetchData();
}, []);
if (loading) return <div>Loading analytics...</div>;
if (error) return <div style={{color: 'red'}}>{error}</div>;
return <div>Data loaded: {data.length} items</div>;
}What just happened?
Axios errors have three types: response (server error), request (network issue), or setup (config problem). Each gets different handling. Try this: Click the error buttons to see how each scenario displays different messages to users.
Interceptors and Global Configuration
Interceptors are middleware for your API calls. Add authentication tokens, log all requests, transform responses globally. Set them once, benefit everywhere:// api.js - Interceptors setup
import axios from 'axios';
const api = axios.create({
baseURL: 'https://api.dataflow.com',
timeout: 10000
});
// Request interceptor - add auth token
api.interceptors.request.use(
(config) => {
const token = localStorage.getItem('authToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
console.log('Making request:', config.method, config.url);
return config;
},
(error) => Promise.reject(error)
);
// Response interceptor - handle common errors
api.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
localStorage.removeItem('authToken');
window.location.href = '/login';
}
return Promise.reject(error);
}
);
export default api;Common Axios Gotcha
Interceptors run for ALL requests made by that Axios instance. Don't add user-specific logic that should only run in certain components. Keep interceptors global and generic.
Request Cancellation and Cleanup
Users navigate away. Components unmount. Cancel ongoing requests to avoid memory leaks and stale updates. Axios makes this clean with AbortController:// Canceling requests in React components
import React, { useState, useEffect } from 'react';
import api from './api';
function SearchResults({ query }) {
const [results, setResults] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (!query) return;
const controller = new AbortController();
setLoading(true);
const searchData = async () => {
try {
const response = await api.get('/search', {
params: { q: query },
signal: controller.signal
});
setResults(response.data);
} catch (error) {
if (error.name !== 'AbortError') {
console.error('Search failed:', error);
}
} finally {
setLoading(false);
}
};
searchData();
// Cleanup: cancel request if component unmounts
return () => controller.abort();
}, [query]);
return (
<div>
{loading && <div>Searching...</div>}
{results.map(item => (
<div key={item.id}>{item.title}</div>
))}
</div>
);
}What just happened?
The cleanup function cancels the previous request when the query changes. This prevents race conditions where a slow request returns after a fast one, showing stale results. Try this: Type quickly and watch how only the latest search completes.
Quiz
1. The DataFlow team is comparing API approaches. What's the main advantage of axios.get('/users') over fetch('/users')?
2. DataFlow needs to add auth tokens to all API calls. How do Axios interceptors work?