Show a pending content boundary
Give one profile screen a visible asynchronous lifecycle.
Table of contents
APIs used
- mount
- Starts a Valyrian.js application on a DOM target.
- Suspense
- Renders fallback while asynchronous children resolve, then renders the result or error output.
Run this recipe
- Starting project
- Use the local TSX and ESM project from Stage 1 with Valyrian.js installed and its ESM browser build configured.
- File
- Replace src/client-entry.tsx with this recipe snippet.
- Run
- Run npm run build, serve public with npx --yes serve@14.2.5 public --listen 8000, open http://localhost:8000 and use the example's visible controls.
- Observable result
- Load profile shows fallback before success. Load rejected profile shows the same fallback before the error renderer.
Starting point
Wrap profile content in a pending boundary with an explicit fallback.
Steps
Give Suspense a new suspenseKey for each action, provide fallback and error renderers, and pass the delayed asynchronous profile as its child.
tsximport { mount } from "valyrian.js";
import { Suspense } from "valyrian.js/suspense";
type Outcome = "success" | "error";
const state = { outcome: "success" as Outcome, run: 0 };
const wait = (milliseconds: number) =>
new Promise((resolve) => setTimeout(resolve, milliseconds));
async function Profile({ outcome }: { outcome: Outcome }) {
await wait(700);
if (outcome === "error") {
throw new Error("Profile request failed");
}
return <p>Loaded profile</p>;
}
function load(outcome: Outcome) {
state.outcome = outcome;
state.run += 1;
}
const Screen = () => {
const suspenseKey = `profile:${state.outcome}:${state.run}`;
return (
<main>
<button onclick={() => load("success")}>Load profile</button>
<button onclick={() => load("error")}>Load rejected profile</button>
<Suspense
suspenseKey={suspenseKey}
fallback={<p>Loading profile...</p>}
error={(error) => <p>{String(error)}</p>}
>
<Profile outcome={state.outcome} />
</Suspense>
</main>
);
};
mount("body", Screen);Result
Load profile shows fallback before success. Load rejected profile shows the same fallback before the error renderer.
Limits
Each action changes suspenseKey and starts a fresh asynchronous run.