forked from polka_billy/porridger
Added type definitions for components, functions, data Added guards for network responses fixes #8
65 lines
2.1 KiB
TypeScript
65 lines
2.1 KiB
TypeScript
import { useEffect, useRef, useState } from "react"
|
|
import { isAborted } from '../../utils'
|
|
|
|
const useFetch = <T>(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<AbortController>()
|
|
|
|
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
|