A lightweight React hook that fetches JSON data into component state using plain `fetch` + `useEffect`, intentionally avoiding any external data-fetching library (no react-query, no QueryClient required). ## Key Components ### `UseSelfFetchResult` Return type interface exposing: - `data` — fetched payload or `null` - `setData` — imperative state setter for optimistic updates - `isLoading` — boolean loading indicator - `error` — boolean error flag - `reload()` — forces a re-fetch (error-retry affordance) ### `useSelfFetch(url, options?)` Core hook with two optional config values: - `options.initialData` — seeds state from SSR-rendered data, skipping the initial fetch - `options.revalidateOnVisibleAfterMs` — opt-in tab-visibility revalidation; re-fetches when the held data is older than the given threshold (replaces `setInterval` polling) ## Usage Example ```typescript // Basic self-fetch const { data, isLoading, error, reload } = useSelfFetch( '/api/products?page=1' ) // SSR-hydrated: skips first fetch, re-fetches on url change const { data, setData } = useSelfFetch( `/api/roadmap?section=${section}`, { initialData: serverData } ) // With tab-visibility revalidation (5 minutes) const { data } = useSelfFetch( '/api/releases', { revalidateOnVisibleAfterMs: 5 * 60 * 1000 } ) // Optimistic update (e.g. upvote) setData((prev) => prev ? { ...prev, votes: prev.votes + 1 } : prev) ``` ## Behavior Notes - **`url = null`** disables fetching entirely (controlled/SSR mode) - **Stale-request guard** — an `AbortController` + `cancelled` flag prevents race conditions when `url` changes rapidly (e.g. pagination) - **SSR hydration skip** — `dataUrlRef` tracks the URL whose data is currently held; the fetch effect is skipped when it matches, surviving React 18 StrictMode's double-mount in dev - **`reload()`** nulls `dataUrlRef` so the same URL can be re-fetched after an error ## Source [`use-self-fetch.ts`](https://github.com/flamingo-stack/openframe-oss-lib/blob/main/use-self-fetch.ts)