本文へスキップ
バージョン: 0.21

子要素

注意

Children の検査と操作は、多くの場合、アプリケーションで驚くべき、そして説明が難しい動作につながります。これはエッジケースを引き起こし、期待した結果にならないことがよくあります。Children を操作しようとしている場合は、他のアプローチを検討する必要があります。

Yew は、子プロパティの型として Html の使用をサポートしています。ChildrenChildrenRenderer が必要ない場合は、子要素として Html を使用する必要があります。これは Children の欠点がなく、パフォーマンスのオーバーヘッドも低くなります。

一般的な使用方法

ほとんどの場合、コンポーネントが子要素を持つことを許可する場合、コンポーネントがどのような型の子要素を持つのかは気にしません。そのような場合、以下の例で十分です。

use yew::{html, Component, Context, Html, Properties};

#[derive(Properties, PartialEq)]
pub struct ListProps {
#[prop_or_default]
pub children: Html,
}

pub struct List;

impl Component for List {
type Message = ();
type Properties = ListProps;

fn create(_ctx: &Context<Self>) -> Self {
Self
}

fn view(&self, ctx: &Context<Self>) -> Html {
html! {
<div class="list">
{ctx.props().children.clone()}
</div>
}
}
}

高度な使用方法

型指定された子要素

ある型のコンポーネントを子要素としてコンポーネントに渡したい場合は、yew::html::ChildrenWithProps<T> を使用できます。

use yew::{html, ChildrenWithProps, Component, Context, Html, Properties};

pub struct Item;

impl Component for Item {
type Message = ();
type Properties = ();

fn create(_ctx: &Context<Self>) -> Self {
Self
}

fn view(&self, _ctx: &Context<Self>) -> Html {
html! {
{ "item" }
}
}
}

#[derive(Properties, PartialEq)]
pub struct ListProps {
#[prop_or_default]
pub children: ChildrenWithProps<Item>,
}

pub struct List;

impl Component for List {
type Message = ();
type Properties = ListProps;

fn create(_ctx: &Context<Self>) -> Self {
Self
}

fn view(&self, ctx: &Context<Self>) -> Html {
html! {
<div class="list">
{ for ctx.props().children.iter() }
</div>
}
}
}

プロパティ付きの子要素の入れ子

包含コンポーネントが子要素の型を指定している場合、入れ子になったコンポーネントのプロパティにアクセスして変更できます。

use std::rc::Rc;
use yew::prelude::*;

#[derive(Clone, PartialEq, Properties)]
pub struct ListItemProps {
value: String,
}

#[function_component]
fn ListItem(props: &ListItemProps) -> Html {
let ListItemProps { value } = props.clone();
html! {
<span>
{value}
</span>
}
}

#[derive(PartialEq, Properties)]
pub struct Props {
pub children: ChildrenWithProps<ListItem>,
}

#[function_component]
fn List(props: &Props) -> Html {
let modified_children = props.children.iter().map(|mut item| {
let mut props = Rc::make_mut(&mut item.props);
props.value = format!("item-{}", props.value);
item
});
html! { for modified_children }
}

html! {
<List>
<ListItem value="a" />
<ListItem value="b" />
<ListItem value="c" />
</List>
};

列挙型で型指定された子要素

もちろん、場合によっては、子要素をいくつかの異なるコンポーネントに制限する必要があるかもしれません。このような場合、Yew をもう少し詳しく理解する必要があります。

ここでは、より良いエルゴノミクスを実現するために、derive_more クレートが使用されています。使用したくない場合は、各バリアントに対して From を手動で実装できます。

use yew::{
html, html::ChildrenRenderer, virtual_dom::VChild, Component,
Context, Html, Properties,
};

pub struct Primary;

impl Component for Primary {
type Message = ();
type Properties = ();

fn create(_ctx: &Context<Self>) -> Self {
Self
}

fn view(&self, _ctx: &Context<Self>) -> Html {
html! {
{ "Primary" }
}
}
}

pub struct Secondary;

impl Component for Secondary {
type Message = ();
type Properties = ();

fn create(_ctx: &Context<Self>) -> Self {
Self
}

fn view(&self, _ctx: &Context<Self>) -> Html {
html! {
{ "Secondary" }
}
}
}

#[derive(Clone, derive_more::From, PartialEq)]
pub enum Item {
Primary(VChild<Primary>),
Secondary(VChild<Secondary>),
}

// Now, we implement `Into<Html>` so that yew knows how to render `Item`.
#[allow(clippy::from_over_into)]
impl Into<Html> for Item {
fn into(self) -> Html {
match self {
Self::Primary(child) => child.into(),
Self::Secondary(child) => child.into(),
}
}
}

#[derive(Properties, PartialEq)]
pub struct ListProps {
#[prop_or_default]
pub children: ChildrenRenderer<Item>,
}

pub struct List;

impl Component for List {
type Message = ();
type Properties = ListProps;

fn create(_ctx: &Context<Self>) -> Self {
Self
}

fn view(&self, ctx: &Context<Self>) -> Html {
html! {
<div class="list">
{ for ctx.props().children.iter() }
</div>
}
}
}

オプションの型指定された子要素

特定の型の単一のオプションの子コンポーネントを持つこともできます。

use yew::{
html, html_nested, virtual_dom::VChild, Component,
Context, Html, Properties
};

pub struct PageSideBar;

impl Component for PageSideBar {
type Message = ();
type Properties = ();

fn create(_ctx: &Context<Self>) -> Self {
Self
}

fn view(&self, _ctx: &Context<Self>) -> Html {
html! {
{ "sidebar" }
}
}
}

#[derive(Properties, PartialEq)]
pub struct PageProps {
#[prop_or_default]
pub sidebar: Option<VChild<PageSideBar>>,
}

struct Page;

impl Component for Page {
type Message = ();
type Properties = PageProps;

fn create(_ctx: &Context<Self>) -> Self {
Self
}

fn view(&self, ctx: &Context<Self>) -> Html {
html! {
<div class="page">
{ ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }
// ... page content
</div>
}
}
}

// The page component can be called either with the sidebar or without:

pub fn render_page(with_sidebar: bool) -> Html {
if with_sidebar {
// Page with sidebar
html! {
<Page sidebar={html_nested! {
<PageSideBar />
}} />
}
} else {
// Page without sidebar
html! {
<Page />
}
}
}

さらに読む

  • このパターンの現実世界の例については、yew-router のソースコードを確認してください。より高度な例については、メインの yew リポジトリにある入れ子リストの例を確認してください。