State Module API Reference
The state module provides OSUI's powerful, React-like hook system for managing component state and side effects. These hooks enable reactivity, allowing your UI to automatically update in response to data changes.
State<T> Struct
#[derive(Debug)]
pub struct State<T> {
value: Arc<Mutex<T>>,
dependents: Arc<Mutex<Vec<HookEffect>>>,
}
State<T> is the primary type for holding reactive, component-local state. It wraps a value T in an Arc<Mutex<T>> for thread-safe access and includes a list of HookEffects that should be triggered when its value changes.
Methods:
fn get(&self) -> Inner<'_, T>- Acquires a lock on the internal
Mutexand returns anInner<'_, T>guard. This guard provides mutable (DerefMut) access to the state value. When theInnerguard is dropped, if the value was mutated, alldependents(registeredHookEffects) are notified.
- Acquires a lock on the internal
fn get_dl(&self) -> T- "Deadlock-less" getter. Acquires a lock, clones the internal value
T, releases the lock, and returns the cloned value. Useful for reading the state when cloningTis cheap and you don't need mutable access, preventing potential deadlocks from holding aMutexGuardacrossawaitpoints or other blocking operations. RequiresT: Clone.
- "Deadlock-less" getter. Acquires a lock, clones the internal value
fn set(&self, v: T)- Replaces the current state value with
vand then explicitly notifies alldependents.
- Replaces the current state value with
fn update(&self)- Manually triggers all registered
dependents. Useful if you've modified the internal value without usingget()(e.g., viaArc::get_mutif theArcis uniquely owned, which is rare forState<T>).
- Manually triggers all registered
fn clone(&self) -> Self- Clones the
State<T>handle (not the internal value). This creates a newArcreference to the same underlyingvalueanddependents. Essential for movingState<T>into closures or passing to child components without moving the actual state.
- Clones the
Display Implementation:
If T implements std::fmt::Display, State<T> also implements std::fmt::Display, allowing it to be directly formatted (e.g., in format!) by implicitly calling get_dl().
Inner<'a, T> Struct
pub struct Inner<'a, T> {
value: MutexGuard<'a, T>,
dependents: Arc<Mutex<Vec<HookEffect>>>,
updated: bool,
}
A guard type returned by State<T>::get(). It provides scoped, mutable access to the internal state value.
Deref and DerefMut Implementations:
- Allows
Inner<'a, T>to be treated as a&Tor&mut T, giving direct access to the underlying state. - The
DerefMutimplementation sets an internalupdatedflag.
Drop Implementation:
- When
Inner<'a, T>is dropped, if theupdatedflag istrue, it automatically iterates throughdependentsand calls theircall()method, ensuring reactivity.
HookEffect Struct
#[derive(Clone)]
pub struct HookEffect(Arc<Mutex<dyn FnMut() + Send + Sync>>);
A wrapper around a mutex-protected closure that represents a side effect. These are registered as dependents of State<T> or Mount and are triggered when dependencies change.
Methods:
fn new<F: Fn() + Send + Sync + 'static>(f: F) -> Self- Creates a new
HookEffectfrom a given closure.
- Creates a new
fn call(&self)- Executes the wrapped closure by acquiring its mutex.
HookDependency Trait
pub trait HookDependency: Send + Sync {
fn on_update(&self, hook: HookEffect);
}
The HookDependency trait defines how an object can register an effect (HookEffect) to be triggered when it updates.
Implementations:
State<T>: Registers theHookEffectto be called whenState<T>'s value changes (viaset(),get()and subsequent drop, orupdate()).Mount: Registers theHookEffectto be called whenmount()is invoked, or immediately if already mounted.
Mount Struct
#[derive(Debug, Clone)]
pub struct Mount(Arc<Mutex<bool>>, Arc<Mutex<Vec<HookEffect>>>);
A specialized hook for managing component lifecycle (specifically, the "mounted" state). It tracks whether a component has been mounted and queues HookEffects to be run upon mounting.
Methods:
fn mount(&self)- Sets the internal flag to
true, indicating the component is now mounted. - Executes all currently queued
HookEffects and clears the queue. - Any
HookEffectregistered aftermount()has been called will execute immediately.
- Sets the internal flag to
Hooks Functions
These functions are the primary way to interact with the state management system within your components.
fn use_state<T>(v: T) -> State<T>
- Purpose: Creates and initializes a new
State<T>instance. - Usage:
let count = use_state(0);
fn use_effect<F: FnMut() + Send + Sync + 'static>(f: F, dependencies: &[&dyn HookDependency])
- Purpose: Registers a side effect
fthat will run when any of thedependencieschange, and also once initially. The effect closure is run in astd::thread::spawn. - Usage:
let counter = use_state(0);
use_effect(
{ let counter = counter.clone(); move || println!("Counter changed: {}", counter.get_dl()) },
&[&counter] // Dependencies
); - Empty Dependencies: If
dependenciesis&[], the effect runs once on initial render and never again.
fn use_mount() -> Mount
- Purpose: Creates a
Mountinstance that is immediately marked as "mounted". Effects registered with thisMount(viause_effect) will run once, immediately. - Usage:
let mount_hook = use_mount();
fn use_mount_manual() -> Mount
- Purpose: Creates a
Mountinstance that starts in an "unmounted" state. Effects registered with thisMountwill only run when its.mount()method is explicitly called (either programmatically or via!mount_hook_instanceinrsx!). - Usage:
let manual_mount_hook = use_mount_manual();
fn use_sync_state<T, E, D>(cx: &Arc<Context>, v: T, decoder: D) -> State<T>
- Purpose: Creates a
State<T>that automatically updates its value whenever an event of typeEis emitted to the givenContext. Thedecoderfunction converts&Einto a newT. - Usage:
// Assume MessageChangeEvent is defined
let message_state = use_sync_state(
cx,
"Default message".to_string(),
|event: &MessageChangeEvent| event.0.clone()
);
fn use_sync_effect<T, Ev, E>(cx: &Arc<Context>, state: &State<T>, encoder: E, deps: &[&dyn HookDependency])
- Purpose: Registers an effect that emits an event
Evto the givenContextwhenever the monitoredstatechanges (or any other specifieddeps). Theencoderfunction converts&State<T>into anEv. - Usage:
let count_state = use_state(0);
// Assume CounterUpdatedEvent is defined
use_sync_effect(
cx,
&count_state,
|s: &State<i32>| CounterUpdatedEvent { new_value: s.get_dl() },
&[&count_state]
);
These hooks provide a complete and reactive state management solution, enabling dynamic and interactive TUI applications in OSUI.
Next: Delve into the details of the Macros API.