Skip to content

Reactivity

Store state on the View. render reads that state to build elements. Call cx.invalidate() after a mutation so the window redraws.

#Reactive state

Keep fields on the view struct. Register listeners with cx.listener so events can mutate those fields.

struct Counter {
    count: usize,
}
impl View for Counter {
    fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> impl IntoElement {
        let increment = cx.listener("increment", |this, cx: &mut EventContext| {
            this.count += 1;
            cx.invalidate();
        });
        div()
            .child(text(format!("Count: {}", self.count)))
            .child(button().on_click(increment).child("Increment"))
    }
}

A value you copy in render is the current frame’s snapshot.

#Derived state

Compute derived values in render from the fields you already store.

let doubled = self.count * 2;
text(format!("{doubled}"))

Store an expensive derivation on the view when several children need the same value in one frame.

#Effects and cleanup

Start external work from listeners or Application callbacks, and stop it when the view is dropped. Closing a window drops the view and its listeners.

impl Drop for WatcherView {
    fn drop(&mut self) {
        self.stop.take().map(|stop| stop());
    }
}

#Batched updates

Calling cx.invalidate() marks the window dirty. Multiple invalidations in one event become one render. Do not install a timer to redraw when nothing changed.