Low-Level Design : Retry Mechanism on API Failure in React
📌 Problem Statement
In modern web applications, network requests (API calls) can occasionally fail due to reasons such as:
Without a retry mechanism, these failures result in poor user experience, broken flows, or loss of data submission. Users may need to refresh the page or manually retry, which is inefficient.
There is a need to design a robust, reusable retry mechanism in React that:
✅ Solution Overview
We will design a Reusable API Call Hook with Retry Support using:
⚙️ Detailed Design
1. Key Components
2. Flow Diagram
3. Hook: useRetryApi Example
import { useState, useCallback } from 'react';
const useRetryApi = (apiFn, maxRetries = 3, retryDelay = 1000) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [retryCount, setRetryCount] = useState(0);
const fetchData = useCallback(async () => {
setLoading(true);
setError(null);
try {
const response = await apiFn();
setData(response);
} catch (err) {
if (retryCount < maxRetries) {
setRetryCount(retryCount + 1);
setTimeout(fetchData, retryDelay); // Optional: Exponential backoff can be applied here
} else {
setError('Request failed after multiple attempts.');
}
} finally {
setLoading(false);
}
}, [apiFn, retryCount, maxRetries, retryDelay]);
return { data, loading, error, fetchData, retryCount };
};
export default useRetryApi;
4. Usage Example
const ExampleComponent = () => {
const { data, loading, error, fetchData, retryCount } = useRetryApi(() => fetch('/api/data').then(res => res.json()), 3);
return (
<div>
{loading && <p>Loading...</p>}
{error && (
<div>
<p>{error}</p>
<button onClick={fetchData}>Retry Manually</button>
</div>
)}
{data && <div>Data: {JSON.stringify(data)}</div>}
{!loading && !data && <button onClick={fetchData}>Fetch Data</button>}
</div>
);
};
5. Best Practices
✅ Summary
The Retry Mechanism improves reliability and user experience in React applications by: