UNPKG

fetchninjax

Version:

A smart React hook for handling fetches with retry, caching, and more

106 lines (85 loc) 2.44 kB
import { useEffect, useRef, useState } from "react"; const cacheStore = new Map(); function useSmartFetch(url, options = {}) { const { method = "GET", headers = {}, body = null, timeout = 10000, retry = 0, retryDelay = attempt => Math.min(1000 * 2 ** attempt, 10000), refreshInterval = null, cache = false, cacheTime = 60000, onSuccess, onError, customFetcher } = options; const [data, setData] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const controllerRef = useRef(null); const intervalRef = useRef(null); const fetchData = async (attempt = 0) => { setLoading(true); setError(null); if (controllerRef.current) { controllerRef.current.abort(); } controllerRef.current = new AbortController(); const signal = controllerRef.current.signal; const cached = cacheStore.get(url); if (cache && cached && Date.now() - cached.timestamp < cacheTime) { setData(cached.data); setLoading(false); return; } try { let responseData; if (customFetcher) { responseData = await customFetcher(); } else { const response = await fetch(url, { method, headers, body, signal }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } responseData = await response.json(); } if (cache) { cacheStore.set(url, { data: responseData, timestamp: Date.now() }); } setData(responseData); onSuccess && onSuccess(responseData); } catch (err) { if (err.name === "AbortError") return; if (attempt < retry) { setTimeout(() => fetchData(attempt + 1), retryDelay(attempt)); return; } setError(err); onError && onError(err); } finally { setLoading(false); } }; useEffect(() => { fetchData(); if (refreshInterval) { intervalRef.current = setInterval(fetchData, refreshInterval); } return () => { controllerRef.current?.abort(); clearInterval(intervalRef.current); }; }, [url]); return { data, error, loading }; } export default useSmartFetch;