RustのフレームワークYewを使ってみる③
前回までのあらすじ
ファンクションコンポーネントを分けたり、プロパティを使って表示を変えてみたりしました。
use yew::prelude::*;
use gloo_console::log;
#[derive(Properties, PartialEq)]
pub struct Props {
#[prop_or(true)]
pub is_loading: bool,
}
#[function_component]
fn Login(props: &Props) -> Html {
log!("LOGIN was loaded");
if props.is_loading {
//trueのときの処理
html! {
<>
<p>{"LOGIN"}</p>
<p>{format!("is_loading: {}", props.is_loading)}</p>
</>
}
} else {
//falseのときの処理
html! {
<>
<p>{"LOGOUT"}</p>
<p>{format!("is_loading: {}", props.is_loading)}</p>
</>
}
}
}
#[function_component]
pub fn App() -> Html {
log!("App was loaded");
html! {
<main>
<h1>{ "Hello World!!" }</h1>
<Login />
<span>{ "Rust with Yew test" }</span>
</main>
}
}
プログラムを分割する
app.rsにたくさんのプログラムを書いて行くと可読性・保守性が低下してしまいます。
プログラムの中で、function_componentとして分かれていますが、プログラムが増えていくと、読みにくくなっていきます。そこで、ファイルを分けてapp.rsにモジュールとして読み込ませようと思います。
srcフォルダの下にappという名前でフォルダを作成します。フォルダ命名には規則があり、app.rsの子モジュールとなるため、フォルダ名はappとしなければなりません。
作成したappフォルダの中にhello.rsとsubtittle.rsを作成します。
Yewproject/
├── yewapp/
│ ├── dist
│ ├── src
│ │ ├── app
│ │ │ └── login.rs
│ │ ├── app.rs
│ │ └── main.rs
│ ├── target
│ ├── Cargo.lock
│ ├── Cargo.toml
│ ├── Dockerfile
│ ├── index.html
│ └── index.scss
└── docker-compose.yml
app.rsのからLogin関数をlogin.rsに移します。
use yew::prelude::*;
use gloo_console::log;
#[derive(Properties, PartialEq)]
pub struct Props {
#[prop_or(true)]
pub is_loading: bool,
}
#[function_component]
pub fn Login(props: &Props) -> Html {
log!("LOGIN was loaded");
if props.is_loading {
//trueのときの処理
html! {
<>
<p>{"LOGIN"}</p>
<p>{format!("is_loading: {}", props.is_loading)}</p>
</>
}
} else {
//falseのときの処理
html! {
<>
<p>{"LOGOUT"}</p>
<p>{format!("is_loading: {}", props.is_loading)}</p>
</>
}
}
}
Loginをapp.rsで使用するために、login.rsをモジュールとして読み込み、Login関数を使用できるようにプログラムを追加します。
use yew::prelude::*;
use gloo_console::log;
mod login;
use login::Login;
#[function_component]
pub fn App() -> Html {
log!("App was loaded");
html! {
<main>
<h1>{ "Hello World!!" }</h1>
<Login />
<span>{ "Rust with Yew test" }</span>
</main>
}
}
app.rsがシンプルになったので、app.rsのプログラムををmain.rsにまとめてしまっても良いかもしれません。
use yew::prelude::*;
use gloo_console::log;
mod login;
use login::Login;
#[function_component]
pub fn App() -> Html {
log!("App was loaded");
html! {
<main>
<h1>{ "Hello World!!" }</h1>
<Login />
<span>{ "Rust with Yew test" }</span>
</main>
}
}
fn main() {
yew::Renderer::<App>::new().render();
}
この場合のフォルダ構成は、以下のようになります。
Yewproject/
├── yewapp/
│ ├── dist
│ ├── src
│ │ ├── login.rs
│ │ └── main.rs
│ ├── target
│ ├── Cargo.lock
│ ├── Cargo.toml
│ ├── Dockerfile
│ ├── index.html
│ └── index.scss
└── docker-compose.yml
コールバックを使ってみる
コールバックを使ってonclickイベントを処理できるようにしてみる。
yew公式を参考にSubtittle関数のspanタグにブレース付きでonclickイベントを追加し、Callbackオブジェクトonclickを作成して、クリックされたときの動作を記述する。#[function_component]
pub fn App() -> Html {
log!("App was loaded");
// onclickが設定されたspanタグがクリックされたときの動作(コンソールにログを表示)
let onclick = Callback::from(move |_| {
log!("span-tag was clicked");
});
html! {
<main>
<h1>{ "Hello World!!" }</h1>
<Login />
<span {onclick}>{ "Rust with Yew test" }</span>
</main>
}
}
let onclick = Callback::from(move |_| {…});で、Callbackオブジェクトonclickを作成します。このコールバックは、クリックイベント発生時に呼び出される関数を指定します。Callback::fromメソッドは、クロージャを引数として受け取り、それをコールバックに変換します。
spanタグに対してクリックイベントを設定し、{onclick} のように属性として onclickコールバックを指定します。これにより、ユーザーがspanタグをクリックすると、指定されたクリックハンドラ関数が呼び出されます。
move |_| { log!("span-tag was clicked"); } は、クリックハンドラ関数です。この関数は無名クロージャとして定義されており、クリックされたときに呼び出され、コンソールに"span-tag was clicked"というメッセージを出力します。
Callbackオブジェクトを代入する変数名を任意に指定したい
今後、onclickイベントが増えた場合、Callbackオブジェクトを代入する変数名を任意に指定したいので、プログラムを少し書き換えてみる。
spanタグにonlickイベントに{click_span}を追加して、Callbackオブジェクトもclick_spanに合わせて書き換え。
#[function_component]
pub fn App() -> Html {
log!("App was loaded");
// onclickが設定されたspanタグがクリックされたときの動作(コンソールにログを表示)
let click_span = Callback::from(move |_| {
log!("span-tag was clicked");
});
html! {
<main>
<h1>{ "Hello World!!" }</h1>
<Login />
<span onclick={click_span}>{ "Rust with Yew test" }</span>
</main>
}
}
Callbackオブジェクトの部分を|:MouseEvent|クロージャに置き換えて書くことも可能なようです。|:MouseEvent|クロージャをclick_spanに束縛して、クリックされたときの動作を記述した感じになります。
let click_span = |_:MouseEvent| {
log!("span-tag was clicked");
};
クリックされたことだけが必要なので、クリックイベントハンドラがクリックに関連する情報(たとえば、クリックの座標やボタンの情報など)を受け取る必要はなく、引数を使用しません。クロージャの引数を使用しない(無視する)にも関わらず、クロージャの引数に'_'を使用しているのは、コンパイラの警告を回避するためです。
次回
inuput要素をためしたい。
Discussion