Suspense¶
Primitives behind PythonNative's async rendering model: the
Suspend signal, the
standard asyncio tasks that run async def component bodies, cached async values
(Resource /
start_resource), and code splitting
with lazy.
The user-facing pieces are the Suspense
boundary component (documented with the other
components) and the
use_resource hook (documented with the
other hooks); this page covers the underlying machinery.
Suspense resources backed by standard asyncio tasks.
Also home to run_eagerly, the
driver behind async def components: it steps a coroutine once
synchronously and only hands the remainder to a task when the first
await is really pending, so bodies whose awaits are already resolved
render inline without a fallback flash.
Classes:
| Name | Description |
|---|---|
Suspend |
Signal that a render is blocked on pending async work. |
Resource |
A cached async value with Suspense integration. |
Functions:
| Name | Description |
|---|---|
start_resource |
Start |
run_eagerly |
Start |
lazy |
Define a component that loads its implementation on first render. |
Suspend
¶
Bases: BaseException
Signal that a render is blocked on pending async work.
Raised while a component renders, either by
Resource.read or by an
async def component body blocking on a pending await. The
reconciler catches it: the nearest
Suspense boundary shows its fallback
(initial mounts), or the component keeps its previous content and
re-renders when the work finishes (updates).
Derives from :class:BaseException so
ErrorBoundary (which catches
:class:Exception) never mistakes a suspension for a crash.
Attributes:
| Name | Type | Description |
|---|---|---|
waitable |
The pending work; exposes |
|
hook_state |
The suspended component's hook state, carried so a Suspense boundary can preserve it across retries (its cached resources survive, so the retry doesn't refetch). |
|
key |
Optional[Tuple[int, Any]]
|
|
label |
Component name for diagnostics. |
Resource
¶
Resource(driver: Future[T])
Bases: Generic[T]
A cached async value with Suspense integration.
Returned by use_resource. A resource
starts fetching as soon as the hook runs and remembers its result
across renders (until its dependencies change), so re-renders never
refetch.
Two ways to consume it:
resource.read()in a regular component: returns the value when ready, re-raises the fetcher's error if it failed, and suspends the render while pending.await resourcein anasync defcomponent: same semantics, expressed as a plain await.
Methods:
| Name | Description |
|---|---|
read |
Return the fetched value, or suspend the render while pending. |
cancel |
Cancel the in-flight fetch (no-op when already done). |
Attributes:
| Name | Type | Description |
|---|---|---|
ready |
bool
|
Whether the fetch has finished (successfully or not). |
read
¶
Return the fetched value, or suspend the render while pending.
Raises:
| Type | Description |
|---|---|
Suspend
|
While the fetch is still in flight (caught by the reconciler, never by user code). |
BaseException
|
Whatever the fetcher raised, re-raised so an
enclosing |
start_resource
¶
Start fetcher immediately and wrap it in a Resource.
The fetcher may be an async def (typical) or a plain function;
synchronous results resolve the resource immediately, so reading
it never suspends.
This is the non-hook constructor used for module-level resources
(preloading data before a screen mounts) and by
lazy. Inside components, prefer
use_resource, which caches per
component instance and re-fetches when dependencies change.
run_eagerly
¶
Start coro now and return a future for its result.
The first step of the coroutine runs synchronously, in a copy of the
caller's context (so provider values and the installed hook state
survive later await boundaries, exactly as in an
:class:asyncio.Task). If the body finishes in that step, the
returned future is already done; if it suspends, the rest of the
body is driven by a task owned by scope and the returned object
is that task.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
coro
|
Coroutine[Any, Any, T]
|
The coroutine to drive. |
required |
scope
|
Any
|
The |
required |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
When |
lazy
¶
Define a component that loads its implementation on first render.
loader runs once, the first time the returned component
renders; until it resolves, renders suspend (so wrap usages in a
Suspense boundary to show a loading
state). The loaded value must be a component (a @component
function or any element factory).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
loader
|
Callable[[], Any]
|
A zero-arg callable returning the component, or an
|
required |
Returns:
| Type | Description |
|---|---|
Callable[..., Any]
|
A component. Props (and children) pass through to the loaded |
Callable[..., Any]
|
component unchanged. |
Next steps¶
- Walk through async components,
Suspense, anduse_resourceend-to-end: Async + data guide. - See how suspension threads through the render pass: Architecture.