React Error Handling & Retry Strategies
Building robust React applications means anticipating errors and handling them gracefully. Whether it’s network failures, API errors, or unexpected exceptions, proper error handling ensures your app doesn’t crash and keeps users informed. Additionally, retry strategies help recover from temporary issues automatically.
Why Error Handling is Important

- User Experience: Display friendly messages instead of broken pages.
- Reliability: Ensure the app continues working despite errors.
- Debugging: Log and track errors for developers to fix issues.
- Data Integrity: Avoid incomplete or corrupted data being shown to users.
Basic Error Handling in React
In functional components, you can handle errors using try-catch blocks during API calls:
import React, { useState, useEffect } from "react";
function UserList() {
const [users, setUsers] = useState([]);
const [error, setError] = useState(null);
useEffect(() => {
const fetchUsers = async () => {
try {
const response = await fetch("<https://jsonplaceholder.typicode.com/users>");
if (!response.ok) throw new Error("Failed to fetch users!");
const data = await response.json();
setUsers(data);
} catch (err) {
setError(err.message);
}
};
fetchUsers();
}, []);
if (error) return <p>Error: {error}</p>;
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
export default UserList;
- Wrap API calls in a
try-catchblock. - Set an error state and display it to the user.
- Prevents the app from crashing on network or server errors.
Retry Strategies
Sometimes errors are temporary (e.g., network issues). You can implement retry logic to automatically re-fetch data:
import React, { useState, useEffect } from "react";
function fetchWithRetry(url, retries = 3, delay = 1000) {
return new Promise((resolve, reject) => {
const attempt = (n) => {
fetch(url)
.then((res) => {
if (!res.ok) throw new Error("Request failed");
return res.json();
})
.then(resolve)
.catch((err) => {
if (n === 0) reject(err);
else setTimeout(() => attempt(n - 1), delay);
});
};
attempt(retries);
});
}
function RetryExample() {
const [data, setData] = useState([]);
const [error, setError] = useState(null);
useEffect(() => {
fetchWithRetry("<https://jsonplaceholder.typicode.com/users>")
.then(setData)
.catch((err) => setError(err.message));
}, []);
if (error) return <p>Error: {error}</p>;
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
export default RetryExample;
fetchWithRetryattempts multiple fetch calls with a delay.- Reduces failure chances due to temporary network issues.
- Improves robustness of your React application.
Using React Query / SWR for Automatic Retry
Libraries like React Query or SWR handle retrying failed requests automatically, along with caching, background refetching, and error states.
React Query Example:
import { useQuery } from "@tanstack/react-query";
function Users() {
const { data, error, isLoading } = useQuery(
["users"],
() => fetch("<https://jsonplaceholder.typicode.com/users>").then(res => res.json()),
{
retry: 3, // retry failed requests 3 times
retryDelay: 1000,
}
);
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{data.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
- Automatic retries reduce boilerplate code.
- Built-in error handling states:
isLoading,error. - Simplifies robust API integration in React apps.
