Make the interface react
Give one value a home, update it from a button, and watch only its readers refresh.
Outcome: every click updates an on-screen counter with one small, shared state value.
01
Meet State in three friendly steps
State<T> is a small clonable object that points to one value on the UI thread. Every clone reaches the same value, so the button and text can cooperate.
Create one source
State::new(0_u32) stores the current count. Keep that small shared object near the application setup.
Share the same value
Cloning State does not duplicate the count. It gives another small object that points to the same reactive value.
Let widgets observe it
A Text widget reads the derived memo during retained work. Only reads made inside an active retained callback become subscriptions; ordinary reads elsewhere are passive.
02
Build the smallest useful counter
This counter stays small enough to read in two passes: first create the shared value, then connect the visible text and button.
Build it in small steps
Each code block changes one idea from the verified reference application.
Step 1: create and derive
State::new stores the number. to_text_with creates a reactive text value from it.
let count = State::new(0_u32);
let count_label = count.to_text_with(|value| format!("{value} tiny wins"));
let count_for_view = count.clone();
Step 2: read and update from the view
The Text observes the derived value. The button calls update and schedules the next visible refresh.
Card::elevated().width(420.0).child(
Column::new()
.gap(16.0)
.child(Text::new("Make one value move").size(26.0))
.child(Text::new(count_label.clone()).size(20.0))
.child(
Button::<()>::with_label("Add one").on_click_ctx(move |_ctx| {
count_for_click.update(|value| *value += 1);
}),
),
)
}),
)Compiled with Rust 1.88 against beta.2. State::update, State::to_text_with, Text::new, and Button::on_click_ctx are public APIs.
03
Read the example like a tiny story
There are only three moving parts. Follow them once and the reactive pattern becomes pleasantly repetitive.
1. Store
Create count once before App::new so the value survives every content rebuild.
2. Describe
to_text_with turns the number into a lazy String memo that Text can read directly.
3. Update
The click handler calls update. Every clone shares the new stored number, and retained readers are scheduled for the refresh they need.
Three small details worth remembering
Clone the State object to share it between functions. State::read clones the stored value, and set or update still notify readers when the new value equals the old one in beta.2.
Try it yourself
Exercise: make the counter smarter
Extend the counter with one safe mutation and one derived label.
- 1Add a button that subtracts one with saturating_sub so the value never goes below zero.
- 2Create a second derived text that displays Even or Odd.
Use update for the subtraction and to_text_with for the derived label.
Both labels refresh after every click and repeated subtraction stops at zero.