import { useEffect, useState, useCallback } from "react"; /* * Voert `fn({ signal })` uit zodra `deps` veranderen; annuleert een lopende * aanroep bij een nieuwe. `delay` (ms) debounced — handig voor typen-en-zoeken. * Geeft { data, error, loading, reload }. */ export function useAsync(fn, deps, { delay = 0 } = {}) { const [state, setState] = useState({ data: null, error: null, loading: true }); const [tick, setTick] = useState(0); useEffect(() => { const ctrl = new AbortController(); setState((s) => ({ ...s, loading: true, error: null })); const t = setTimeout(() => { fn({ signal: ctrl.signal }) .then((data) => { if (!ctrl.signal.aborted) setState({ data, error: null, loading: false }); }) .catch((e) => { if (e.name !== "AbortError") setState((s) => ({ ...s, error: e.message, loading: false })); }); }, delay); return () => { clearTimeout(t); ctrl.abort(); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [...deps, tick]); const reload = useCallback(() => setTick((n) => n + 1), []); return { ...state, reload }; }