Lifecycle and Runtime Loop
One of the easiest mistakes when learning Ansiq is to blur these two things together:
- the app lifecycle
- the runtime’s update loop
They are related, but they answer different questions.
First: the app lifecycle
At a high level, a Ansiq app usually goes through:
- create the app
- enter the terminal session
- call
mount(...) - perform the first
render(...) - enter the runtime loop
- repeatedly handle input, messages, and rerender work
- exit and restore the terminal
This answers:
what phases does an app go through over its lifetime?
Second: the runtime loop
The runtime loop answers a different question:
once some change happens, how does Ansiq turn that change into a stable terminal update?
Ansiq currently coordinates:
- input events
- app messages
- reactive flushes
- rerender decisions
- partial relayout
- invalidated regions
- framebuffer diff
- terminal patch emission
The four important App methods
pub trait App {
type Message: Send + 'static;
fn mount(&mut self, _handle: &RuntimeHandle<Self::Message>) {}
fn render(&mut self, cx: &mut ViewCtx<'_, Self::Message>) -> Element<Self::Message>;
fn update(&mut self, message: Self::Message, handle: &RuntimeHandle<Self::Message>);
fn on_unhandled_key(
&mut self,
_key: Key,
_handle: &RuntimeHandle<Self::Message>,
) -> bool {
false
}
}mount(...)
Use mount(...) for work that should exist as soon as the app starts:
- start a sampler
- open a long-lived connection
- emit an initial message
It is not the place where UI gets drawn.
render(...)
render(...) describes the current UI tree and establishes the reactive reads for that render.
It does not emit patches directly.
update(...)
update(...) consumes messages and turns them into app state changes.
It answers:
- what did the user do?
- what new fact arrived from background work?
- how should that fact change app state?
on_unhandled_key(...)
If no widget consumes a key and the runtime does not consume it for global focus navigation, the key can still bubble back to the app.
This is useful for:
- global shortcuts
Escapeto cancel- mode switches
- command entry
fn on_unhandled_key(
&mut self,
key: Key,
handle: &RuntimeHandle<Self::Message>,
) -> bool {
if key == Key::Esc {
let _ = handle.emit(Message::Cancel);
return true;
}
false
}Why this is not “just an event loop”
In simpler UI systems, the loop can feel like “receive an event, redraw once”.
That is not enough for Ansiq because the runtime also has to coordinate:
- async messages
- localized rerender
- localized relayout
- viewport and history behavior
So the runtime loop is an architectural boundary, not just an implementation detail.
Next
Continue with Reactivity and Reactive System in Depth.
The first page teaches how to use signal, computed, and effect; the second explains why the reactive graph stays separate from the UI tree.