resource()
For client-side async data, resource() formalizes the fetch-into-signals pattern — components stay synchronous, and the view renders the resource's reactive states:
import { resource, router } from "@opentf/afw";
export default function UserProfile() {
const user = resource(
() => router.params.id, // reactive source — re-fetches when it changes
async (id, { signal }) => {
const response = await fetch(`/api/users/${encodeURIComponent(id)}`, { signal });
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
return response.json();
},
);
return (
<div>
{user.error ? <p>Failed: {user.error.message}</p> :
user.loading ? <p>Loading…</p> :
user.data ? <h1>{user.data.name}</h1> : <p>No user selected.</p>}
</div>
);
}resource(fetcher)fetches once;resource(source, fetcher)re-fetches when the reactivesourcechanges;{ initial }seedsdata.Each run aborts the previous run's
AbortController(the fetcher receives{ signal }) and late, out-of-order resolutions are discarded.A rejection sets
errorand keeps the last gooddata; the next success clears it.refetch()re-runs manually.A
sourcereturningnull/falsepauses fetching (conditional resources).invalidate()refetches every live resource and reloads the page's loader data;invalidate(listTodos)only the resources that called that server function.During SSG/SSR nothing fetches and
loadingstaystrue, so the prerendered HTML shows your loading branch and hydration stays aligned.A resource created in a component stops when the component is removed: its fetch is aborted and it no longer refetches.
{ errors: "inline" }keeps failures onerroronly, even inside a<Pending>.
Related
Loading States: one loading state for every resource inside a
<Pending>.Server functions: typed calls a resource can fetch from.