diff --git a/README.md b/README.md index 220a252..3ef25af 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,13 @@ The shared footer keeps the StableRoute tagline visible on every page, renders t The frontend communicates with the StableRoute API backend. +### Data-fetching convention + +Data-backed pages should use the shared `useApi` hook from `src/lib/useApi.ts` +for `loading` / `ok` / `error` state handling and unmount cancellation instead +of hand-rolled `useEffect` fetch logic. This keeps live regions, error states, +and cleanup behavior consistent across pages. + ### Environment Variables - **`NEXT_PUBLIC_STABLEROUTE_API_BASE`**: Specifies the base URL of the StableRoute API backend (defaults to `http://localhost:3001` if unset). diff --git a/src/app/pairs/Client.tsx b/src/app/pairs/Client.tsx index 27e29ca..3dbb936 100644 --- a/src/app/pairs/Client.tsx +++ b/src/app/pairs/Client.tsx @@ -1,21 +1,15 @@ "use client"; -import { useEffect, useState } from "react"; import Link from "next/link"; -import { apiGet } from "@/lib/apiClient"; +import { useApi } from "@/lib/useApi"; type Pair = { source: string; destination: string }; export default function PairsClient() { - const [pairs, setPairs] = useState(null); - const [error, setError] = useState(null); - const isLoading = pairs === null && error === null; - - useEffect(() => { - apiGet<{ pairs: Pair[] }>("/api/v1/pairs") - .then((b) => setPairs(b.pairs)) - .catch((e) => setError(e.message)); - }, []); + const pairsState = useApi<{ pairs: Pair[] }>("/api/v1/pairs"); + const isLoading = pairsState.status === "loading"; + const error = pairsState.status === "error" ? pairsState.error : null; + const pairs = pairsState.status === "ok" ? pairsState.data.pairs : null; return (