Boundaries
Components that fetch data or do async work need loading and error states. Effex provides two boundary types: suspense for async rendering and error for catching failures.
Suspense
Wrap async components in a suspense boundary to show a fallback while they load:
import { Boundary } from "@effex/dom";
Boundary.suspense({
render: () =>
Effect.gen(function* () {
const user = yield* fetchUser(id);
return yield* UserProfile({ user });
}),
fallback: () => $.div({}, $.of("Loading...")),
catch: (error) => $.div({}, $.of(`Error: ${error.message}`)),
delay: "200 millis", // Avoid loading flash for fast responses
});
The delay option prevents the fallback from showing if the async work completes quickly. If fetchUser resolves within 200ms, the user sees the content directly — no loading flicker.
How It Works
- Effex starts rendering the
renderfunction - If it encounters an async Effect that isn’t resolved yet, it shows the
fallback - When the async work completes, the fallback is replaced with the real content
- If the async work fails, the
catchhandler renders instead
Error Boundary
Catch errors from a component subtree without crashing the whole app:
Boundary.error(
() => RiskyComponent(),
(error) => $.div({}, $.of(`Failed: ${error.message}`)),
);
The error handler receives the error and returns an Element to render in place of the failed subtree. The rest of the application continues running.
Combining Boundaries
Boundaries compose naturally. You can nest suspense inside error boundaries, or vice versa:
Boundary.error(
() =>
Boundary.suspense({
render: () => DataDashboard(),
fallback: () => DashboardSkeleton(),
}),
(error) => $.div({}, $.of("Dashboard unavailable")),
);
This catches both sync errors (thrown during render) and async failures (rejected Effects).