@zoijs/resource
The simplest way to read async data. A resource wraps a fetcher and gives you reactive loading, data, and error states.
npm install @zoijs/core @zoijs/resourceExample#
import { html, mount } from "@zoijs/core";
import { resource } from "@zoijs/resource";
function Profile() {
const user = resource(() => fetch("/api/user").then((r) => r.json()));
return html`
${() =>
user.loading() ? html`<p>Loading…</p>`
: user.error() ? html`<p>Couldn't load.</p>`
: html`<h1>${user.data().name}</h1>`}
`;
}
mount(Profile, "#app");It runs the fetcher once on creation. The three readers are reactive — read them inside a binding and the DOM updates when the data arrives.
API#
| Member | What it gives you |
|---|---|
resource(fetcher) | Create a resource; loads immediately |
data() | The loaded value, or undefined before the first success |
loading() | true while a load is in flight |
error() | The error, or null |
refresh() | Load again (keeps old data until the new load resolves) |
Pairs with @zoijs/action for writes: resource reads, action writes.
Error monitoring#
A failure that becomes error() is also reported to the app's configure({ onError }) hook from @zoijs/core, as { kind: "resource" } with the original error (superseded or post-unmount results aren't reported). It goes through the core's shared runtime, so a no-build import map needs no extra entry. Reports need @zoijs/core 1.9.0 or later — older cores have no shared runtime, so nothing is reported (and nothing breaks).
import { configure } from "@zoijs/core";
configure({ onError: (error, info) => reportToMonitoring(error, info.kind) });Known limitations#
- No cache, request dedupe, or retries — each
resource(...)is its own state. - SSR hand-off: pass
{ initial }to start settled with server data — serialize it with @zoijs/ssr'sserializeand the resource keeps it on hydration instead of refetching. Per-request data loaders aren't included.