Cheatsheet
Quick reference for common patterns.
See the full CHEATSHEET.md in the repository root.
Quick snippets
Basic app
struct App;
impl Component for App {
fn render(&self, cx: Scope) -> View {
View::text("Hello")
}
}
fn main() { telex::run(App).unwrap(); }
State
let count = state!(cx, || 0);
count.get() // read
count.set(5) // write
count.update(|n| *n += 1) // modify
Callbacks
with!(count => move || count.update(|n| *n += 1))
Layouts
View::vstack().child(...).child(...).build()
View::hstack().child(...).child(...).build()
Button
View::button().label("Click").on_press(callback).build()
Input
View::text_input().value(v.get()).on_change(cb).build()
List
View::list().items(vec).selected(idx).on_select(cb).build()
Modal
View::modal().visible(show.get()).on_dismiss(cb).child(...).build()
Table
View::table()
.column("Name")
.column("Value")
.rows(data)
.selected(idx)
.on_select(cb)
.build()
TextArea
View::text_area()
.value(text.get())
.rows(10)
.on_change(with!(text => move |s| text.set(s)))
.build()
Tabs
View::tabs()
.tab("Home", home_view)
.tab("Settings", settings_view)
.active(tab.get())
.on_change(with!(tab => move |idx| tab.set(idx)))
.build()
Dynamic Data
Stream
let data = stream!(cx, || {
(0..).map(|i| {
std::thread::sleep(Duration::from_secs(1));
i
})
});
View::text(format!("{}", data.get()))
Effect (one-time)
effect_once!(cx, || {
println!("Component mounted!");
|| {} // cleanup
});
Effect (with dependency)
effect!(cx, count.get(), |&val| {
println!("Count: {}", val);
|| {} // cleanup
});
Async
let data = async_data!(cx, || {
fetch_from_api()
});
match &data {
Async::Loading => View::text("Loading..."),
Async::Ready(d) => View::text(d),
Async::Error(e) => View::text(e),
}
Channel
let ch = channel!(cx, String);
// ch.tx() gives WakingSender to pass to threads
// ch.get() returns this frame's messages
Port (bidirectional)
let io = port!(cx, InMsg, OutMsg);
// io.rx.tx() / io.rx.get() for inbound
// io.tx() / io.take_outbound_rx() for outbound
Interval
interval!(cx, Duration::from_secs(1), with!(count => move || {
count.update(|n| *n += 1);
}));
Reducer
let (state, dispatch) = reducer!(cx, initial, |s, a| {
match a { /* ... */ }
});
Slider
View::slider()
.min(0.0).max(100.0).step(1.0)
.value(val.get())
.label("Volume")
.on_change(with!(val => move |v: f64| val.set(v)))
.build()
Error Boundary
View::error_boundary()
.child(risky_view)
.fallback(View::text("Something went wrong"))
.build()
Custom Widget
View::custom(Rc::new(RefCell::new(my_widget)))
Keyboard Commands
Bind a key
cx.use_command(
KeyBinding::key(KeyCode::Char('s')).ctrl(true),
with!(data => move || save(data.get()))
);
Multiple modifiers
KeyBinding::key(KeyCode::Char('q'))
.ctrl(true)
.shift(true)
Common Patterns
Toggle boolean
show.update(|v| *v = !*v)
Conditional state (safe in if/else)
if condition {
let data = state!(cx, || Vec::new());
}
Add to list
items.update(|v| v.push(new_item))
Remove from list
items.update(|v| {
if idx < v.len() {
v.remove(idx);
}
})
Clear list
items.update(|v| v.clear())
For more examples, see the full CHEATSHEET.md in the repository.