Resumable: async data

The page loader fetches the initial data on the server; it lands in a signal, serializes into the island, and resumes on the client — the list shows without the component running. The Refresh button is an async handler that await fetch()s: it lifts verbatim, so on click it reloads data and updates the signal — still without re-running the component.

Tip
The list below is server-rendered and resumed (no component execution on load). Click "Refresh" — the async handler fetches new data from /api/resumable-feed and the count + list update. Each fetch returns an increasing number to prove the round-trip.

Live demo


3 items · server (SSR)
• Server-rendered item 1 • Server-rendered item 2 • Server-rendered item 3
Feed.tsxTSX
"use resumable";
import { signal } from "@bext-stack/framework/signals";

// The page loader fetches the initial data and passes it as props →
// it lands in a signal, serializes into the island, and RESUMES on the
// client (the component never runs).
export default function Feed(props) {
  const items = signal(props.items ?? []);
  return (
    <div>
      {/* an ASYNC handler — lifts verbatim into __rh, awaits fetch on the
          client, and updates the signal. No component re-run. */}
      <button onClick={async () => {
        const r = await fetch("/api/resumable-feed");
        items.value = (await r.json()).items;
      }}>Refresh</button>
      <div>{items.value.length} items</div>
    </div>
  );
}