リアクティビティ
状態は View に保持します。render はその状態を読んで要素を組み立てます。変更したあとに cx.invalidate() を呼び出すと、ウィンドウが再描画されます。
#リアクティブな状態
フィールドはビューの構造体に置きます。イベントがそれらのフィールドを変更できるよう、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}"))同じフレームで複数の子が同じ値を必要とするときは、コストの高い派生結果をビューに保持します。
#副作用とクリーンアップ
外部の処理はリスナーまたは Application のコールバックから開始し、ビューがドロップされたときに止めます。ウィンドウを閉じると、ビューとそのリスナーがドロップされます。
impl Drop for WatcherView {
fn drop(&mut self) {
self.stop.take().map(|stop| stop());
}
}#更新のバッチ処理
cx.invalidate() を呼び出すと、ウィンドウは再描画が必要だとマークされます。1 つのイベント内の複数の無効化は、1 回の描画になります。何も変わっていないときに再描画するタイマーは置かないでください。
