アプリの状態を管理する
UIデータを保持して更新します。
「アプリの状態を管理する」はCoddyKit上の無料Learn Rust Codingレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLearn Rust Coding学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Learn Rust Codingコースには全4レッスンが含まれています。
App構造体に状態を保持する
eguiでは、アプリケーションの状態はeframe::Appを実装する構造体に保持する、通常のRustデータです。専用のストアや、フレームワークが所有するモデルはありません。
フォームの入力値、選択項目、読み込んだデータ、フラグなど、必要なものはすべてフィールドに保持します。各フレームでupdateが&mut selfを通してこれらのフィールドを直接読み書きします。
struct App {
query: String,
results: Vec<Item>,
selected: Option<usize>,
loading: bool,
}Defaultの自動導出
eframeは、run_nativeに渡したクロージャ内でアプリを構築します。最も簡単なパターンは、#[derive(Default)]を使い、App::default()で構築する方法です。
デフォルト以外の初期値が必要な場合は、Defaultを手動で実装するか、CreationContextを受け取るコンストラクターを追加します。フォントや永続化などのセットアップにも利用できます。
impl App {
fn new(cc: &eframe::CreationContext) -> Self {
let mut app = Self::default();
app.dark = cc.egui_ctx.style().visuals.dark_mode;
app
}
}唯一の信頼できるデータソース
ウィジェットは、値を保持するフィールドを&mutで借用するため、構造体が常に唯一の信頼できるデータソースになります。同期すべき別のビュー状態はありません。
&mut self.enabledに結び付けたチェックボックスは、そのboolを直接表示・更新します。同じフレーム内の別の場所で読み取れば、更新後の値を確認できます。
ui.checkbox(&mut self.enabled, "Enabled");
if self.enabled {
ui.label("Feature is on");
}変更を遅延させる
微妙な借用の問題があります。Vecを反復処理しながら、その中から要素を削除したくなることがあります。しかし、共有借用が有効な間はvecを変更できません。
この場合は、ループ中に実行したい操作をローカル変数へ記録し、ループ終了後に適用します。
let mut to_remove = None;
for (i, item) in self.items.iter().enumerate() {
ui.horizontal(|ui| {
ui.label(&item.name);
if ui.button("x").clicked() { to_remove = Some(i); }
});
}
if let Some(i) = to_remove { self.items.remove(i); }enumで画面を管理する
複数画面のアプリでは、現在のビューをenum型のフィールドとして表します。updateメソッドでその値をマッチさせ、何を描画するかを決めます。
これにより、ナビゲーションを明示的かつ網羅的に管理できます。コンパイラーがすべての画面の処理を要求するため、さまざまなルーティングバグを防げます。
enum Screen { Home, Settings, About }
match self.screen {
Screen::Home => self.draw_home(ui),
Screen::Settings => self.draw_settings(ui),
Screen::About => self.draw_about(ui),
}UI状態用のeguiメモリ
折りたたまれたセクション、スクロール位置、ドラッグ状態など、ドメインではなくUIだけに関係する状態もあります。eguiはこれらをウィジェットのIdをキーとしてctx.memoryに保存します。
直接操作することはほとんどありませんが、ctx.data_mutを使えば、アプリ構造体を複雑にせず、フレーム間で保持されるIDごとの小さな値を保存できます。
let id = egui::Id::new("my_toggle");
let mut open = ctx.data_mut(|d| d.get_temp::<bool>(id).unwrap_or(false));
ui.checkbox(&mut open, "Open");
ctx.data_mut(|d| d.insert_temp(id, open));チャネルを使ったバックグラウンド処理
遅いI/Oでupdateを決してブロックしないでください。60fpsのループが停止してしまいます。スレッドを起動し、std::sync::mpscチャネルで通信します。
ワーカーが結果を送り、updateは各フレームでtry_recvを使って受信側からブロックせずに取り出します。データが到着したときにUIを再開できるよう、ワーカーからctx.request_repaint()を呼び出します。
if let Ok(msg) = self.rx.try_recv() {
self.results = msg;
self.loading = false;
}ワーカーを起動する
Contextと送信側をクローンしてスレッドに渡します。内部ではArcなのでクローンのコストは小さく、ワーカーから再描画を要求できるようになります。
借用チェッカーを満たし、ライフタイムの問題を避けるため、処理に必要な入力の所有権をクロージャへ移します。
let tx = self.tx.clone();
let ctx = ctx.clone();
std::thread::spawn(move || {
let data = expensive_load();
let _ = tx.send(data);
ctx.request_repaint();
});状態を永続化する
eframeでは、アプリの状態を実行間でシリアライズできます。persistence機能を有効にし、serde::Serialize / Deserializeを導出して、App::saveを実装します。
起動時には、コンストラクターでcc.storageから保存済み状態を読み取ります。何も保存されていない場合はデフォルト値に戻します。
fn save(&mut self, storage: &mut dyn eframe::Storage) {
eframe::set_value(storage, eframe::APP_KEY, self);
}
// in new():
if let Some(s) = cc.storage {
if let Some(app) = eframe::get_value(s, eframe::APP_KEY) { return app; }
}updateを軽く保つ
updateはフレームごとに実行されるため、そこで高コストな派生データを再計算しないようにします。結果をフィールドにキャッシュし、入力が変わったときだけ再計算します。
よくあるパターンは、Response::changed()でdirtyフラグを設定し、updateの先頭でdirtyの場合にだけキャッシュを再構築する方法です。
if self.dirty {
self.filtered = self.filter_items();
self.dirty = false;
}
for item in &self.filtered { ui.label(&item.name); }所有権が状態を明確に保つ
繰り返し登場する重要な考え方は、eguiが状態管理をフレームワークではなくRustの所有権に委ねていることです。構造体がデータを所有し、&mut selfがフレームごとに排他的なアクセスを与え、スレッドはチャネルを通して通信します。
隠れたサブスクリプションやコールバックのグラフがないため、状態がいつ、どのように変わるかを局所的かつ明示的に把握できます。
理解度チェック
時間のかかるネットワーク取得は、どのように実行すべきですか。
まとめ
アプリの状態はeframe::App構造体の通常のフィールドに保持し、各フレームで&mut selfを通して変更します。そのため、構造体が唯一の信頼できるデータソースになります。
反復処理中の変更は遅延させ、画面はenumで表現し、時間のかかる処理はチャネルを使ってスレッドに移し、eframeのストレージで状態を永続化します。dirtyフラグを使って派生データをキャッシュし、updateを軽く保ちます。次は、配布用にアプリをパッケージ化する方法を学びます。
AI チューターと学ぶ Rust — 無料
ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。
- コース
- 39
- レッスン
- 144
よくある質問
「アプリの状態を管理する」レッスンは無料ですか?
はい。「アプリの状態を管理する」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Learn Rust Codingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Learn Rust Codingコースには全4レッスンが含まれています。
「アプリの状態を管理する」で何を学びますか?
UIデータを保持して更新します。 ブラウザで直接実行するハンズオンコードでLearn Rust Codingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Learn Rust Codingを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのLearn Rust Codingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「アプリの状態を管理する」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このLearn Rust Codingレッスンでコードを書いて実行できますか?
はい。すべてのLearn Rust Codingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。