import { useEffect, useRef, useState } from "react" import { isAborted } from '../../utils' const useFetch = (url: string, params: RequestInit | undefined, initialData: T, dataGuard: (obj: unknown) => obj is T) => { const [data, setData] = useState(initialData) const [loading, setLoading] = useState(true) const [error, setError] = useState("") const abortControllerRef = useRef() useEffect(() => { if (abortControllerRef.current) { abortControllerRef.current.abort() } const abortController = new AbortController() abortControllerRef.current = abortController fetch(url, { ...params, signal: abortControllerRef.current.signal }) .then(res => { if (!res.ok) { switch (res.status) { case 401: throw new Error("Ошибка авторизации") case 404: throw new Error("Объект не найден") default: { throw new Error("Ошибка ответа от сервера") } } } return res.json() }) .then(data => { if (!dataGuard(data)) { throw new Error("Неверный ответ от сервера") } setData(data) setLoading(false) }) .catch(err => { if (err instanceof Error && !isAborted(err)) { setError("Ошибка сети") } setLoading(false) if (import.meta.env.DEV) { console.log(url, params, err) } }) return () => abortControllerRef.current?.abort() }, [url, params, dataGuard]) return { data, loading, error, abort: abortControllerRef.current?.abort.bind(abortControllerRef.current) } } export default useFetch