Loading States¶
Handling asynchronous data fetching with appropriate loading indicators.
Problem¶
You need to fetch data asynchronously and show appropriate feedback while loading.
Solution¶
Track loading state explicitly and render skeletons, spinners, or error messages.
Complete Example¶
This example simulates async work with setTimeout so it’s runnable without network access:
import { createApp, ui, rgb } from "@rezi-ui/core";
import { createNodeBackend } from "@rezi-ui/node";
type LoadingState<T> =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: T }
| { status: "error"; error: string };
type User = { id: string; name: string };
type State = {
users: LoadingState<User[]>;
};
const app = createApp<State>({
backend: createNodeBackend(),
initialState: { users: { status: "idle" } },
});
function fetchUsers(): void {
app.update((s) => ({ ...s, users: { status: "loading" } }));
setTimeout(() => {
const ok = Math.random() > 0.2;
if (!ok) {
app.update((s) => ({ ...s, users: { status: "error", error: "Failed to load users" } }));
return;
}
app.update((s) => ({
...s,
users: {
status: "success",
data: [
{ id: "1", name: "Ada" },
{ id: "2", name: "Linus" },
{ id: "3", name: "Grace" },
],
},
}));
}, 600);
}
function renderUsers(state: State) {
switch (state.users.status) {
case "idle":
return ui.button({ id: "load", label: "Load Users", onPress: fetchUsers });
case "loading":
return ui.column({ gap: 1 }, [
ui.spinner({ label: "Loading…" }),
ui.skeleton(15),
ui.skeleton(15),
ui.skeleton(15),
]);
case "error":
return ui.empty("Error", {
description: state.users.error,
action: ui.button({ id: "retry", label: "Retry", onPress: fetchUsers }),
});
case "success":
return ui.column({ gap: 1 },
state.users.data.map((user) => ui.text(user.name, { key: user.id }))
);
}
}
app.view((state) =>
ui.column({ flex: 1, gap: 1, p: 1 }, [
ui.text("Users", { style: { bold: true } }),
ui.divider(),
renderUsers(state),
])
);
app.keys({ q: () => app.stop(), "ctrl+c": () => app.stop() });
await app.start();
Explanation¶
- Model async work explicitly with a tagged union (
idle/loading/success/error). - Render a skeleton/spinner while loading.
- Use an empty/error state with a retry action on failure.