State を使ってアプリの状態を管理する

Recipe ID: rust-006

Rust 側でアプリケーションの状態(データベース接続、アプリ全体の設定、キャッシュデータなど)を保持し、それを複数のコマンドからアクセスできるようにする方法を解説します。

グローバル変数を使う代わりに、Tauri が提供する「State(状態)管理機能」を使うのが安全で一般的です。

1. 状態(State)を定義する

まず、保持したいデータを「構造体(struct)」として定義します。

// 状態として保持したいデータを構造体にまとめる
struct AppState {
    db_path: String,
    app_name: String,
}

2. 初期化して Tauri に登録する

lib.rs (または main.rs) のビルド設定部分で、.manage() メソッドを使ってインスタンスを登録します。
これにより、Tauri はこのデータを内部で管理してくれるようになります。

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        // ここで AppState のインスタンスを作成して登録(manage)する
        .manage(AppState {
            db_path: "/tmp/mydb.sqlite".into(), // .into() は &str から String への変換
            app_name: "MyTauriApp".into(),
        })
        .invoke_handler(tauri::generate_handler![read_config])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

3. コマンドから利用する

コマンドの引数に state: tauri::State<'_, AppState> を追加すると、Tauri が自動的に管理している AppState を渡してくれます。これを「依存性の注入(Dependency Injection)」と呼びます。

// 引数に tauri::State を指定するだけでOK
#[tauri::command]
fn read_config(state: tauri::State<'_, AppState>) -> String {
    // state.フィールド名 でアクセスできます
    // 基本的に「読み取り専用」としてアクセスされます
    format!("App: {}, DB: {}", state.app_name, state.db_path)
}

注意点

  • 読み取り専用: 上記の方法では、データの読み取りはできますが、書き換え(変更)はできません
  • 書き換えたい場合: データを書き換える必要がある場合は、次のレシピ (rust-007) で解説する Mutex (ミューテックス) を使う必要があります。

フロントエンド側のコード

import { invoke } from '@tauri-apps/api/core';

async function checkConfig() {
  const config = await invoke('read_config');
  console.log(config); // "App: MyTauriApp, DB: /tmp/mydb.sqlite"
}