0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Dioxus】Propsの型を明示して渡す

Posted at

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!マクロが無い代わりに,ビルダーパターンを用いることでintodefaultの恩恵を受けられます.

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に変換されてしまいます).

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?