はじめに
Tauri + Yew の構成で、Events の listen と emit を試してみました!
この記事では、サンプルコードを使って、Yew で Events を使うやり方を紹介します。
サンプルについて
今回扱うサンプルでは、 Tauri が emit した文字列を Yew が listen し、画面に描画するアプリケーションを作成します。
サンプルコードの全体は、こちらで公開しています。
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 を使うことができます。