LoginSignup
1
1

【Tauri + Yew】Yew で Tauri の Events 使ってみた

Last updated at Posted at 2024-01-27

はじめに

Tauri + Yew の構成で、Events の listen と emit を試してみました!
この記事では、サンプルコードを使って、Yew で Events を使うやり方を紹介します。

サンプルについて

今回扱うサンプルでは、 Tauri が emit した文字列を Yew が listen し、画面に描画するアプリケーションを作成します。

image.png

サンプルコードの全体は、こちらで公開しています。
https://github.com/heptaliane/tauri-yew-events-sample

セットアップ

まずは Tauri + Yew の構成を作成します。
create-tauri-app を使うことで、簡単に基本的な構成を作ることができます。

cargo create-tauri-app sample-app --template yew --manager cargo

Tauri 側のコードの作成

まずは Tauri 側のコードを実装します。

注意すべき点としては、Yew の起動前に emit してしまうと、Yew が Event を取得できません。
そのため今回は、Yew からの emit をトリガーに Tauri が Yew に emit を行うように実装します。
(それって実質 command と変わらないのでは)

イベント名としては、以下を設定することにします。

  • Tauri -> Yew: back-to-front
  • Yew -> Tauri: front-to-back
use tauri::Manager;

fn main() {
    tauri::Builder::default()
        .setup(|app| {
            let app_handle = app.app_handle();
            // Yew -> Tauri のメッセージを待ち受け
            let _  = app.listen_global("front-to-back", move |_| {
                // Tauri -> Yew に メッセージを送信
                app_handle
                    .emit_all("back-to-front", "tauri-yew-events-sample".to_string())
                    .unwrap();
            });
            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

Yew 側の実装

UI の作成

src/app.rs を編集し、文字列を表示する UI を作ります。

use yew::prelude::*;

#[function_component(App)]
pub fn app() -> Html {
    let msg = use_state(|| String::new());

    html! {
        <span>{(*msg).clone()}</span>
    }
}

@tauri-apps/api/event の bind

Events のドキュメントを読むと、js では@tauri-apps/api/event の関数を使用しています。
これを Yew でも扱えるようにするため、 wasm-bindgen で listen と emit を import します。

use wasm_binggen::prelude::*;

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = ["window", "__TAURI__", "event"])]
    async fn listen(event: &str, handler: &Closure<dyn FnMut(JsValue)>) -> JsValue;

    #[wasm_bindgen(js_namespace = ["window", "__TAURI__", "event"])]
    async fn emit(event: &str, payload: JsValue);
}

Yew -> Tauri イベントの emit

Tauri へ front-to-back イベントを emit します。
今回は Tauri 側で payload を使用しないため、メッセージに null を入れることにしましょう。

use_effect_with_deps in yew::functional - Rust を参考に、
component の初回作成時のみで、front-to-back イベントが発生するようにしておきます。

use wasm_bindgen_futures::spawn_local;

#[function_component(App)]
pub fn app() -> Html {
    ...

    use_effect_with_deps(
        move |_| {
            spawn_local(async move {
                emit("front-to-back", JsValue::NULL).await;
            });
        },
        (),
    );

    ...
}

Tauri -> Yew イベントの listen

Tauri からの back-to-front イベントを listen します。

Event オブジェクト の定義

Tauri からのメッセージは、Event オブジェクトとして送信されます。
これを Yew で扱うため、オブジェクトの JsValue を deserialize するための struct を定義します。
今回は必要な payload だけを定義しておきます。

use serde::Deserialize;

#[derive(Deserialize)]
struct Payload {
    payload: String,
}

back-to-front イベントの listen

まずは空のイベントハンドラを使ってイベントを listen します。

#[function_component(App)]
pub fn app() -> Html {
    let msg = use_state(|| String::new());

    spawn_local(async move {
        let handler = Closure::<dyn FnMut(JsValue)>::new(move |_event: JsValue| {});
        let _ = listen("back-to-front", &handler).await;
        handler.forget();
    });
    ...
}

続いてイベントハンドラ中で、 Event オブジェクトを deserialize します。

use serde_wasm_bindgen::from_value;

#[function_component(App)]
pub fn app() -> Html {
    let msg = use_state(|| String::new());

    spawn_local(async move {
        let handler = Closure::<dyn FnMut(JsValue)>::new(move |event: JsValue| {
            if let OK(event) = from_value::<Payload>(payload) {}
        });
        let _ = listen("back-to-front", &handler).await;
        handler.forget();
    });
    ...
}

event の値で msg の値を更新します。

use serde_wasm_bindgen::from_value;

#[function_component(App)]
pub fn app() -> Html {
    let msg = use_state(|| String::new());

    {
        let msg = msg.clone();
        spawn_local(async move {
            let handler = Closure::<dyn FnMut(JsValue)>::new(move |payload: JsValue| {
                if let Ok(res) = from_value::<Payload>(payload) {
                    msg.set(res.payload);
                }
            });
            let _ = listen("back-to-front", &handler).await;
            handler.forget();
        });
    }
    ...
}

アプリケーションのビルド

tauri.conf.json を編集し、 identifier を適当な値に設定しておきましょう。

{
  "tauri": {
    "bundle": {
      "identifier": "tauri-yew-events-sample"
      }
    }
  }
}

tauri build コマンドで build すると、target/release/ 配下にアプリケーションが生成されます。

cargo tauri build

まとめ

Yew で Tauri の Events を使う方法を紹介しました。

wasm_bindgen を使って @tauri-apps/api/event をバインドすることで、Yew で listen や emit を使うことができます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1