响应式
把状态保存在 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。没有变化时不要安装定时器来重绘。
