Resources

createResource ties an async data flow to a host element's lifecycle. On the client, it starts in each connect pass after attribute sync, the initial render or hydration and @bindTo, just before onConnected(), so the first fetch sees authored prop values. It aborts in-flight work on disconnect and resumes from the current source on reconnect.

Server rendering never connects Element Hosts, so it does not start resource fetches. Fetch server data before rendering and pass resolved values through initialize, prepareHost, or host attributes.

import { createResource } from '@ecopages/radiant';

Basic Usage

Fetch once on connect — no reactive source needed:

private data = createResource(this, {
	fetcher: (ctx) => fetch('/api/data', { signal: ctx.signal }).then((r) => r.json()),
});

Sourced Usage

Drive fetches from a reactive source. Source changes abort the previous request and start a new one.

source only re-runs when it reads a signal (or a host member backed by one). Prefer @state / @prop so plain property access tracks automatically:

@state activeCityId = 'venice';
 
private weatherQuery = createResource(this, {
	source: (ctx) => ctx.host.activeCityId,
	fetcher: (cityId, ctx) => fetchWeatherReport(cityId, ctx.signal),
	onSuccess: (report) => console.log(report),
});
 
override render() {
	const status = this.weatherQuery.status.get();
	const data = this.weatherQuery.data.get();
	// ...
}

You can also pass a raw signal and call .get() inside source. A plain field is not reactive — changing it will not refetch.

Returning a falsy value (false, null, undefined) from source disables fetching without clearing the current state.

Config Options

OptionTypeDescription
fetcher(source, ctx) => Promise<Value>The async function to call. Without source, receives only ctx. With source, the resolved source value is passed as the first argument. ctx provides host and signal.
source(ctx) => Source | false | null | undefinedA reactive selector that drives re-fetches. Falsy returns pause fetching.
initialValueValueSeed value exposed from data before the first successful resolution.
staleTimenumberMilliseconds a successful response stays fresh in the per-instance cache.
pendingDelaynumberMilliseconds to wait before transitioning status to 'pending'.
onSuccess(data, ctx) => voidCalled after each successful resolution, including cache hits.
onError(error, ctx) => voidCalled after each failed resolution. Not called for aborted requests.
onSettled(data, error, ctx) => voidCalled after each resolution, whether successful or failed.

Return Value

createResource returns a HostResource that implements AsyncStateResult<Value>:

Property / MethodTypeDescription
dataReadonlySignal<Value | undefined>The latest resolved value.
statusReadonlySignal<'idle' | 'pending' | 'success' | 'error'>Current fetch state.
errorReadonlySignal<unknown>The latest rejection reason, if any.
refetch()() => voidRe-runs the fetcher from the current source value.
abort()() => voidAborts the in-flight request.

Lifecycle

connect starts the fetchresolvedrejectedsource change or refetchsource change or refetchidlependingsuccesserror
  1. Connect — after the host's first-connect attribute sync, the resource starts observing the source (or fetches immediately if no source is set).
  2. Source change — the previous request is aborted and a new one starts.
  3. Disconnect — the in-flight request is aborted. The current state is preserved.
  4. Reconnect — the resource resumes from the latest source value.

createResource wires these lifecycle steps automatically.

  • See Weather App for a full sourced resource example with context.
  • createResource builds on the package-level asyncState primitive and adds host lifecycle ownership on top.