Homepage

useFetch

A typed custom hook for handling data fetching operations with built-in loading and error states. This hook simplifies the process of making HTTP requests while maintaining proper state management throughout the request lifecycle.

Implementation


interface FetchResponse<T> {
data: T | null;
loading: boolean;
error: Error | null;
}

interface FetchOptions {
method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
headers?: HeadersInit;
body?: BodyInit | null;
}

function useFetch<T>(url: string, options?: FetchOptions): FetchResponse<T> {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<Error | null>(null);

useEffect(() => {
  const fetchData = async () => {
    try {
      const response = await fetch(url, {
        method: options?.method || 'GET',
        headers: options?.headers,
        body: options?.body,
      });

      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      const jsonData = await response.json();
      setData(jsonData as T);
    } catch (err) {
      setError(err instanceof Error ? err : new Error('An error occurred'));
    } finally {
      setLoading(false);
    }
  };

  fetchData();
}, [url, options]);

return { data, loading, error };
}

Usage

Fetch and display a list of todos

interface Todo {
id: number;
title: string;
completed: boolean;
}

export default function TodoList() {
const { data, loading, error } = useFetch<Todo[]>(
  'https://jsonplaceholder.typicode.com/todos'
);

return (
  <div style={{ padding: '20px' }}>
    {loading && <p>Loading todos...</p>}
    {error && <p>Error: {error.message}</p>}
    {data && (
      <div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
        {data.map(todo => (
          <div 
            key={todo.id}
            style={{
              padding: '10px',
              border: '1px solid #ccc',
              borderRadius: '4px'
            }}
          >
            <h3>
              {todo.completed ? '' : ''}
              {todo.title}
            </h3>
          </div>
        ))}
      </div>
    )}
  </div>
);
}

Parameters

urlstringrequired

The URL to fetch data from

optionsFetchOptions

Optional configuration for the fetch request including method, headers, and body

Return Values

dataT | null

The fetched data when the request is successful, null during loading or on error

loadingboolean

Indicates whether a request is currently in progress

errorError | null

Error object if the request failed, null otherwise

Live Playground

Best Practices

  • Always provide type parameters for better type safety
  • Handle all possible states (loading, error, success) in the UI
  • Use appropriate error boundaries for error handling

Performance Considerations

  • Requests are triggered on url or options changes
  • Consider memoizing options objects to prevent unnecessary re-renders
  • Large responses should be handled with pagination