> The problem is that it requires shared mutable access to that state, which is clunky at best in Rust (it requires interior mutability).

I don't see the problem with using interior mutability (Rc> or Arc>)

With Slint [1], we just embrace it, and rely on interior mutability for the shared state, and that works well.

[1] https://github.com/slint-ui/slint

I tried using interior mutability in rui [1] but the clunkiness appeared in having to call clone on the Rc/Arc too often. I'd have a few clones before moving into a closure, like this:

        let text = self.text.clone();
        focus(move |has_focus| {
            let text = text.clone();
            state(TextEditorState::new(), move |state| {
                let text = text.clone();
                let text2 = text.clone();
                let cursor = state.with(|s| s.cursor);
                let state2 = state.clone();
currently looks like this:

    focus(move |has_focus| {
        state(TextEditorState::new, move |state, cx| {
            let cursor = cx[state].cursor;
            canvas(move |cx, rect, vger| {
(Note the context (cx) passed to callbacks to look things up.)

[1] https://github.com/audulus/rui