SmartCodingTips

🔄 useEffect + fetch (with Loading & Error)

Fetching data in React using useEffect() is a common pattern. Let's enhance our earlier example with a loading spinner and error message.


🛠️ Full Example with Loading & Error Handling


import React, { useEffect, useState } from 'react';

function UsersList() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchUsers = async () => {
      try {
        const res = await fetch('https://jsonplaceholder.typicode.com/users');
        if (!res.ok) throw new Error('Network response was not ok');
        const data = await res.json();
        setUsers(data);
        setError(null);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchUsers();
  }, []);

  if (loading) return <p>Loading users...</p>;
  if (error) return <p style={{ color: 'red' }}>Error: {error}</p>;

  return (
    <div>
      <h2>User List</h2>
      <ul>
        {users.map(user => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  );
}

export default UsersList;
  

🔍 Explanation

  • loading: boolean to show spinner/message before data arrives
  • error: captures any fetch or parsing issues
  • finally ensures loading is turned off in both success/failure cases

This pattern is helpful in real-world apps where user feedback is critical.