my-website-v2/frontend/lib/useFetch.tsx

58 lines
1.4 KiB
TypeScript

import { useEffect } from "preact/hooks";
import { signal } from "@preact/signals";
export function useFetch<T>(
url: string,
options?: FetchOptions,
): {
data: T | null;
loading: boolean;
error: Error | null;
refetch: (newURL?: string, newOptions?: FetchOptions) => void;
} {
const data = signal<T | null>(null);
const loading = signal<boolean>(true);
const error = signal<Error | null>(null);
useEffect(() => {
fetch(url, options)
.then((response) => {
if (!response.ok) {
throw new Error("Failed to fetch data");
}
return response.json();
})
.then((resp) => (data.value = resp))
.catch((err) => (error.value = err))
.finally(() => (loading.value = false));
}, [url, options]);
const refetch = (newURL?: string, newOptions?: FetchOptions) => {
loading.value = true;
error.value = null;
fetch(newURL || url, newOptions || options)
.then((response) => {
if (!response.ok) {
throw new Error("Failed to fetch data");
}
return response.json();
})
.then((resp) => (data.value = resp))
.catch((err) => (error.value = err))
.finally(() => (loading.value = false));
};
return {
data: data.value,
loading: loading.value,
error: error.value,
refetch,
};
}
export interface FetchOptions {
method: "GET" | "POST" | "PUT" | "DELETE";
headers: Record<string, string>;
body: string;
}