import { useCallback, useEffect, useRef, useState } from 'react' // usePolled runs `fn` now and every `everyMs`, and is careful about the two // things every screen would otherwise get wrong on its own: overlapping // requests when the server is slower than the interval, and setting state // after the component has gone. export function usePolled(fn, everyMs, deps = []) { const [data, setData] = useState(null) const [error, setError] = useState(null) const [loading, setLoading] = useState(true) const inFlight = useRef(false) const alive = useRef(true) const run = useCallback(async () => { if (inFlight.current) return inFlight.current = true try { const out = await fn() if (!alive.current) return setData(out) setError(null) } catch (err) { if (!alive.current) return setError(err) } finally { inFlight.current = false if (alive.current) setLoading(false) } // eslint-disable-next-line react-hooks/exhaustive-deps }, deps) useEffect(() => { alive.current = true run() if (!everyMs) return () => { alive.current = false } const t = setInterval(run, everyMs) return () => { alive.current = false; clearInterval(t) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [run, everyMs]) return { data, error, loading, reload: run } }