Lifecycle & Rendering
Lifecycle: on_mount and on_unmount
When a component is inserted into the view tree, the compiler calls its on_mount method (if defined). When removed from the tree, on_unmount is called:
component Connection {
var socket: *u8 = null;
fn on_mount() {
socket = net.connect("localhost", 8080);
}
fn on_unmount() {
net.close(socket);
socket = null;
}
}on_mount— called once after the component is added to the active view treeon_unmount— called once before the component is removed from the view tree
Both are optional. Define either, both, or neither.
Rendering via @dispatch
Visual rendering is not a special compiler feature — it uses the standard dispatch mechanism. Components opt into painting by calling ui.drawable() in a @tape block:
component Panel {
@tape { ui.drawable(); }
prop bg: color;
fn paint(ctx: *u8, x: i32, y: i32, w: i32, h: i32) {
gfx.fill_rect(ctx, x, y, w, h, bg);
}
}ui.drawable() is a comptime function that emits:
pub @tape fn drawable() {
@emit var bounds_x: i64 = 0;
@emit var bounds_y: i64 = 0;
@emit var bounds_w: i64 = 0;
@emit var bounds_h: i64 = 0;
@emit @dispatch fn paint(ctx: *u8, x: i32, y: i32, w: i32, h: i32);
}Layout dispatch
Components that manage child positioning opt into layout:
component MyLayout {
@tape { ui.drawable(); }
@tape { ui.layoutable(); }
fn layout(ctx: *u8, x: i64, y: i64, w: i64, h: i64) {
// position children within bounds
}
fn paint(ctx: *u8, x: i32, y: i32, w: i32, h: i32) {
// draw background
}
}ui.layoutable() emits @dispatch fn layout(...).
Interaction dispatch
Components that handle input opt into the interactive protocol:
component Button {
@tape { ui.drawable(); }
@tape { ui.interactive(); }
fn handle_pointer(ev: *ui.PointerEvent) {
if (ev.kind == ui.PointerKind.Up) {
fire on_click();
}
}
fn handle_key(ev: ui.KeyEvent) {
// keyboard handling
}
}ui.interactive() emits @dispatch fn handle_pointer(ev: *PointerEvent) and @dispatch fn handle_key(ev: KeyEvent).
Rendering cadence
- Input event arrives (pointer, key, timer)
- Event handler executes (may mutate
var/statemultiple times) - Handler returns — dirty flags are set
- Frame tick: runtime walks dirty components
- For each dirty component: recalculate layout if needed, repaint dirty region
- Clear dirty flags
A component is repainted at most once per frame, regardless of how many state mutations occurred.
Dispatch summary
| Capability | Comptime helper | Dispatch methods |
|---|---|---|
| Painting | ui.drawable() | paint(ctx, x, y, w, h) |
| Layout | ui.layoutable() | layout(ctx, x, y, w, h) |
| Input | ui.interactive() | handle_pointer(ev), handle_key(ev) |
Last modified: