Topic 30 of 54
Handling Loading & Error
Overview
Networks are slow and unreliable. If you only track the 'data' state, your users will see a blank screen while the data fetches, or a broken UI if the API crashes. A robust component must track three separate pieces of state: the data itself, a boolean `isLoading` flag, and an `error` object. This provides a professional UX (User Experience).
Syntax
By combining `isLoading` and `error` states with 'Early Return' conditional rendering, we guarantee the user always sees appropriate feedback, and the main UI never attempts to render `null` data.
The Holy Trinity of Fetch State
jsx
function Dashboard() {
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(true); // Start as loading
const [error, setError] = useState(null);
useEffect(() => {
const fetchDashboard = async () => {
setIsLoading(true);
setError(null);
try {
const res = await fetch("/api/dashboard");
if (!res.ok) throw new Error("Failed to fetch");
const json = await res.json();
setData(json);
} catch (err) {
setError(err.message);
} finally {
setIsLoading(false); // ALWAYS runs, success or fail
}
};
fetchDashboard();
}, []);
// Conditional Rendering based on state
if (isLoading) return <p>Loading dashboard...</p>;
if (error) return <p style={{color: 'red'}}>Error: {error}</p>;
return <div><h1>Welcome back!</h1><p>Stats: {data.stats}</p></div>;
}Common Pitfalls
- Forgetting to handle HTTP error codes. `fetch` does NOT throw an error for 404 or 500 status codes. You MUST check `if (!res.ok) throw new Error(...)` manually.
- Accessing `data.property` in the main render without ensuring `data` is not null (which causes a crash).
Interview Tips
- Always include the `finally` block when writing async/await fetches. It ensures that `isLoading` is set to false whether the request succeeds or throws an error, preventing infinite loading spinners.
Real-World Example
Using Skeleton Loaders instead of simple text provides a much better perceived performance.
example
jsx
// Instead of returning <p>Loading</p>
if (isLoading) {
return (
<div className="skeleton-card">
<div className="skeleton-title"></div>
<div className="skeleton-line"></div>
<div className="skeleton-line"></div>
</div>
);
}