rustのフロントエンドフレームワーク(クロスプラットフォームGUIフレームワーク)であるdioxusでは通常rsx!マクロ内で以下のようにプロパティを渡します.
cx.render(rsx! {
TextButton{text:"テキスト", on_click: move |_|{is_clicked.set(true)}}
})
この引数はTextButtonコンポーネントの作成時にdioxus::prelude::Scopeの型パラメーターとして与えたものです.
use dioxus::prelude::*;
#[derive(Props)]
struct TextButtonProps<'a> {
#[props(into)]
text: String,
#[props(default = 1)]
number: usize,
on_click: EventHandler<'a>,
}
fn TextButton<'a>(cx: Scope<'a, TextButtonProps<'a>>) -> Element {
cx.render(rsx! {
div {
(0..cx.props.number).map(|_|
rsx!{
button { onclick: move |_|{cx.props.on_click.call(())},"{cx.props.text}"}
}
)
}
})
}
引数の数が多くてコンパイルエラーの箇所が分かりずらいときなど,場合によってはTextButtonPropsを普通の構造体として作成しコンポーネントに渡したい場合があると思います.
dioxusではそれも可能であり,普通に作成するかビルダーパターンで作成したプロパティをScopeState::componentの引数とするか,baseエクスプレッション(スプレッド構文)を利用することで渡すことができます.yewにおけるprops!マクロが無い代わりに,ビルダーパターンを用いることでintoやdefaultの恩恵を受けられます.
fn App(cx: Scope) -> Element {
let is_clicked = use_state(cx, || false);
let text_button_props_v1 = TextButtonProps {
text: "テキストボタン".to_string(),
number: 2,
on_click: cx.event_handler(move |_| is_clicked.set(true)),
};
let text_button_props_v2 = TextButtonProps::builder()
.text("text button")
.on_click(cx.event_handler(move |_| is_clicked.set(true)))
.build();
cx.render(rsx! {
cx.component(TextButton, text_button_props_v1, "text_button")
TextButton{number: 3, ..text_button_props_v2}
is_clicked.get().then(||
rsx!{div{"クリックされました"}}
)
})
}
コールバックとして渡すクロージャーは明示的にEventHandlerに変換する必要があります.
もちろんチャイルドコンポーネントも渡すことができます.
#[derive(Props)]
struct ChildButtonProps<'a> {
children: Element<'a>,
}
fn ChildButton<'a>(cx: Scope<'a, ChildButtonProps<'a>>) -> Element {
cx.render(rsx! {
button {&cx.props.children}
})
}
fn App(cx: Scope) -> Element {
let child_button_props = ChildButtonProps {
children: cx.render(rsx! {
div{"チャイルドボタン"}
div{"チャイルドボタン"}
}),
};
cx.render(rsx! {
ChildButton{..child_button_props}
ChildButton{"チャイルドボタン2"}
})
}
このプロパティの渡し方はRc<dyn Fn>を引数として渡したいときなどにも便利です(通常の方法ではEventHandlerに変換されてしまいます).