// Created on savesnippets.com ยท https://savesnippets.com/RHNMSKPHCB0XDx import { useEffect, useState } from 'react'; type State = | { status: 'loading' } | { status: 'success'; data: T } | { status: 'error'; error: Error }; export function useFetch(url: string): State { const [state, setState] = useState>({ status: 'loading' }); useEffect(() => { const ctl = new AbortController(); setState({ status: 'loading' }); fetch(url, { signal: ctl.signal }) .then(async r => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.json() as Promise; }) .then(data => setState({ status: 'success', data })) .catch(error => { if (error.name !== 'AbortError') setState({ status: 'error', error }); }); return () => ctl.abort(); }, [url]); return state; }