State Management
Manage application state with message passing.
Pattern
Event → Message → State Update → UI Rebuild
State Struct
#[derive(Default)]
struct AppState {
counter: i32,
username: String,
items: Vec<String>,
}
Messages
enum Message {
Increment,
Decrement,
SetUsername(String),
AddItem(String),
}
Update Function
impl AppState {
fn update(&mut self, msg: Message) {
match msg {
Message::Increment => self.counter += 1,
Message::Decrement => self.counter -= 1,
Message::SetUsername(name) => self.username = name,
Message::AddItem(item) => self.items.push(item),
}
}
}
Connecting to Widgets
// Widget emits message
if let Some(msg) = button.event(&event) {
if msg.downcast_ref::<ButtonClicked>().is_some() {
state.update(Message::Increment);
}
}
// Rebuild UI from state
let ui = Column::new()
.child(Text::new(format!("Count: {}", state.counter)));
Immutability
State should be the single source of truth:
// GOOD: State owns data
struct State { items: Vec<Item> }
// BAD: Widget owns data
struct List { items: Vec<Item> } // Where's the source of truth?
Derived State
Compute from base state:
impl AppState {
fn total(&self) -> i32 {
self.items.len() as i32
}
fn is_empty(&self) -> bool {
self.items.is_empty()
}
}
Verified Test
#[test]
fn test_state_management() {
struct State { count: i32 }
enum Msg { Inc, Dec }
impl State {
fn update(&mut self, msg: Msg) {
match msg {
Msg::Inc => self.count += 1,
Msg::Dec => self.count -= 1,
}
}
}
let mut state = State { count: 0 };
state.update(Msg::Inc);
assert_eq!(state.count, 1);
}