macro_rules! scope {
($key:expr, $s:expr, [$($input:expr),+ $(,)?], $body:block) => { ... };
($key:expr, $s:expr, [], $body:block) => { ... };
}Expand description
Memoized composition scope with input + signal tracking.
Wraps a composable block, caching its output as long as:
- The explicit inputs are unchanged (by
Hashcomparison). - No signal read during body execution has been written since last run.
When the cache is hit, the body is NOT executed -> the previously-composed View is returned instead, with proper ID and composer cursor advancement to keep sibling scopes consistent.
§Usage
use repose_core::*;
fn MyView(s: &mut Scheduler, title: &str, count: i32) -> View {
scope!("my_view", s, [title, count], {
Column(Modifier::new()).child((
Text(title),
Text(format!("Count: {count}")),
))
})
}§Signal auto-tracking
Any Signal::get() call inside the body automatically registers the scope
as a dependency. When that signal is written, the scope is marked dirty and
recomposed on the next frame. You don’t need to put signal values in the
input list -> the reactive system handles dependencies implicitly.
let size = signal(100.0);
scope!("animated", s, [], {
let cur = size.get(); // auto-tracked; cache invalidated on write
Box(Modifier::new().size(cur, cur))
})§f32/f64 in explicit inputs
Float types don’t implement Hash. For float inputs, use .to_bits():
scope!("s", s, [my_float.to_bits()], { ... })Or -> better -> read floats from a Signal<f32> inside the body (auto-tracked).
§Compatibility with remember
remember slots consumed inside the body are tracked and properly advanced
on cache hit, so sibling remember calls remain consistent.