跳到正文

响应式

把状态保存在 View 上。render 读取这些状态来构建元素。变更后调用 cx.invalidate(),窗口才会重绘。

#响应式状态

把字段放在 View 结构体上。用 cx.listener 注册监听器,以便事件能修改这些字段。

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"))
    }
}

在 render 中复制的值是当前帧的快照。

#派生状态

在 render 中根据已有字段计算派生值。

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

当同一帧内多个子节点需要同一个昂贵的派生结果时,把它保存在 View 上。

#副作用与清理

从监听器或 Application 回调启动外部工作,并在 View 被丢弃时停止。关闭窗口会丢弃 View 及其监听器。

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

#批量更新

调用 cx.invalidate() 会把窗口标记为脏。同一次事件中的多次 invalidate 只会触发一次 render。没有变化时不要安装定时器来重绘。