import { useState, useEffect, useCallback } from "react"; /** * Hook for fetching async data with loading and error states. * Handles the common pattern of fetching data when component mounts or dependencies change. * * @param fetcher - Function that returns a Promise with the data * @param options - Configuration options * @returns Object containing data, loading state, error, and refetch function */ export function useAsyncData( fetcher: () => Promise, options: { /** Whether the fetch should be enabled (default: true) */ enabled?: boolean; /** Callback for handling errors */ onError?: (err: unknown) => void; /** Initial data value (useful for optimistic updates) */ initialData?: T; } = {} ): { data: T | null; isLoading: boolean; error: string | null; refetch: () => Promise; } { const { enabled = true, onError, initialData } = options; const [data, setData] = useState(initialData ?? null); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const fetchData = useCallback(async () => { if (!enabled) return; setIsLoading(true); setError(null); try { const result = await fetcher(); setData(result); } catch (err) { const errorMessage = err instanceof Error ? err.message : "Failed to load data"; setError(errorMessage); if (onError) { onError(err); } else { console.error("Failed to fetch data:", err); } } finally { setIsLoading(false); } }, [fetcher, enabled, onError]); useEffect(() => { fetchData(); }, [fetchData]); return { data, isLoading, error, refetch: fetchData, }; }