State, Signals, and Effects
Repose uses a small reactive core instead of an explicit widget tree with mutable fields. There are three main pieces:
Signal<T>— observable, reactive value.remember*— lifecycle‑aware storage bound to composition.effect/scoped_effect— side‑effects with cleanup.
Signals
Signal<T> is a cloneable handle to a piece of state:
use *;
let count = signal;
count.set;
count.update;
assert_eq!;
Reads participate in a dependency graph: when you call get() inside an
observer or produce_state, future writes will automatically recompute that
observer.
Remembered state
UI state is typically held in remember_* slots rather than globals:
use *;
rememberandremember_stateare order‑based: the Nth call in a composition slot always refers to the Nth stored value.remember_with_keyandremember_state_with_keyare key‑based and more stable across conditional branches.
Derived state
produce_state computes a Signal<T> from other signals and recomputes it
automatically when dependencies change:
let first = signal;
let last = signal;
let full = produce_state;
assert_eq!;
Effects and cleanup
Use effect / scoped_effect for one‑off side‑effects with cleanups:
use *;
effectruns once when the view is composed and returns aDisposeguard that will be run when the scope is torn down.scoped_effectis wired to the currentScopeand is cleaned up on scope disposal (e.g. when a navigation entry is popped).
For long‑running tasks (network, timers), prefer building small helpers on
top of scoped_effect so everything cleans up correctly when the UI that
owns it disappears.