😺
Dioxus (Rustでfrontend) 入門1
Dioxus入門1
FrontendをRustで書く意味?
- 趣味...
- WASM Interface Typesが標準化されれば、JSの呼び出し等が高速になる
- RuntimeエラーがReact/Angularに比べて殆どない
- ただし .unwrap()とかexpect()とか不用意に使うとすぐpanicする
- Rust Backend APIのStructを使い回せる
- DioxusならSSR対応(ただしbotがアクセスする用として割り切るべき)
YewではなくDioxusな理由
- SSR対応
- Dioxusのほうが Runtimeエラーがでづらい
- use_futureが便利
- Yewよりいろいろなものがシンプル
- formに対する inputイベントが取れる
- Yewも取れるかもしれませんが ちょっと触った限りではできませんでした。。。
Setup
- trunkをインストール
- rustc webassembly対応に
Cargo.toml
[package]
name = "dixious-test"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dioxus = { version = "0.2.4", features = ["web"] }
dioxus-router = "0.2.3"
web-sys = {"version" = "0.3.44", features=['console']}
gloo = "0.8"
gloo-net = "0.2"
serde = {version = "1", features = ["derive"]}
serde_json = "1"
anyhow="1"
[profile.release]
lto = true
opt-level = 's'
[profile.release]
lto = true
opt-level = 's'
この設定を入れることで release build時のwasmのサイズを小さくできる。
開発時の実行は trunk serve
でweb serverも起動します。
Release Buildは trunk build --release
サンプルコード
Routerをつかってみる
pub fn Route(cx: Scope) -> Element {
cx.render(rsx! {
div {
Router {
dioxus_router::Route {
to: "/login", Login{}
},
dioxus_router::Route {
to: "/", root()
}
}
}
})
}
このようなコードを書けば pathとコンポーネントを紐付けることができる。
Dioxusでは Componentを呼ぶ際、大文字の自作コンポーネントはRSXの中で呼び出すとき、 App{"aaa"} と呼ぶことができる。 {}で囲って呼び出せる。
小文字の場合は app()で呼出すため、使い勝手が異なる。 一般的には頭が大文字の関数を作成することになる。 Warningがでると面倒なので下記をコードに入れることで、コンパイル時の警告をなくすことができる。
#[allow(non_snake_case)]
また、 onclickなど コードで画面遷移したい場合
use_router(&cx).replace_route("/login", None, None);
などとすれば /loginに遷移することができる。 location.href等で飛ばすとjsやwasmが再度ロードされてしまうので注意。
Navigation サイドバーなどでリンクで飛ばしたい場合は下記のようなRSXを書く。
fn app(cx: Scope) -> Element {
cx.render(rsx! {
Router {
Route { to: "/", "Home" }
Route { to: "/games", "Games" }
Route { to: "/play", "Play" }
Route { to: "/settings", "Settings" }
p {
"----"
}
nav {
ul {
Link { to: "/", li { "Home" } }
Link { to: "/games", li { "Games" } }
Link { to: "/play", li { "Play" } }
Link { to: "/settings", li { "Settings" } }
}
}
}
})
Local State
Dioxusでは Reactと同様にuse_stateが利用できる。
このサンプルはDesktop Appを作成するためだが、
mainの中身を下記に入れ替えれば webで利用できる。
dioxus::web::launch(App);
use_future
async fn get_customer_names() -> Result<Vec<String>, anyhow::Error> {
let ls = gloo::storage::LocalStorage::raw();
let token = ls.get_item("token");
if token.is_err() {
return Err(anyhow::anyhow!("token not found"));
}
let token = token.unwrap();
if token.is_none() {
return Err(anyhow::anyhow!("token not found"));
}
let token = token.unwrap();
const URL: &str = "https://graphqlsvr/v1/api/test/graphql";
let token = format!("Bearer {}", token.replace("\"", ""));
let json = Request::post(URL)
.header("authorization", token.as_str())
.body(r#"{"operationName":null,"variables":{},"query":"{\n customers @mysql {\n name\n }\n}\n"}"#.to_string())
.send()
.await?
.text()
.await?;
gloo::console::log!("", &json);
let data: Value = serde_json::from_str(json.as_str())?;
let datas = data
.get("data")
.ok_or(anyhow::anyhow!("data not found"))?
.get("customers")
.ok_or(anyhow::anyhow!("customers not found"))?;
gloo::console::log!("", &datas.to_string());
let names: Vec<String> = datas
.as_array()
.unwrap()
.iter()
.flat_map(|v| v.get("name"))
.map(|v| v.as_str().unwrap_or("").to_string())
.collect();
Ok(names)
}
というgraphqlで顧客名を取得する非同期のコードがあったとき、
pub fn CustomerSelector(cx: Scope) -> Element {
let s = use_state(&cx, || vec!["".to_string()]);
let selected_name = use_state(&cx, || "test".to_string());
{
let s = s.clone();
use_future(&cx, (), |()| async move {
let datas = get_customer_names().await.unwrap_or(vec!["".to_string()]);
gloo::console::log!(format!("{:?}", &datas));
s.set(datas);
});
}
let names = s.get();
let selected_name_string = selected_name.get().to_string();
cx.render(rsx! {
select {
class: "pf-c-form-control",
onchange: move |e| {
let selected_name = selected_name.clone();
gloo::console::log!(e.value.as_str());
selected_name.set(e.value.clone());
},
names.iter().map(|name| rsx!{
option {
"{name}"
}
})
}
CustomerInfo {
name: selected_name_string,
}
})
}
この様に呼び出すことができる。
use_futureはReactのuse_effectのFutureを扱える版である。
Yewとは異なり、DioxusだけでFutureを解決することができる。
Discussion