mirror of
https://github.com/yewstack/yew.git
synced 2025-12-08 21:26:25 +00:00
* change suffixes from md to mdx fix broken links for English locale tree shake and update docusaurus add docusaurus ideal image plugin use svg and themed image delete unused static asset * move localized landing page * change GitLocalize project page * nit pick * remove ignore to have the block checked
253 lines
5.1 KiB
Plaintext
253 lines
5.1 KiB
Plaintext
---
|
|
title: "Children"
|
|
---
|
|
|
|
## General usage
|
|
|
|
_Most of the time,_ when allowing a component to have children, you don't care
|
|
what type of children the component has. In such cases, the below example will
|
|
suffice.
|
|
|
|
```rust
|
|
use yew::{html, Children, Component, Context, Html, Properties};
|
|
|
|
#[derive(Properties, PartialEq)]
|
|
pub struct ListProps {
|
|
#[prop_or_default]
|
|
pub children: Children,
|
|
}
|
|
|
|
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>
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Advanced usage
|
|
|
|
### Typed children
|
|
In cases where you want one type of component to be passed as children to your component,
|
|
you can use `yew::html::ChildrenWithProps<T>`.
|
|
|
|
```rust
|
|
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>
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Enum typed children
|
|
Of course, sometimes you might need to restrict the children to a few different
|
|
components. In these cases, you have to get a little more hands-on with Yew.
|
|
|
|
The [`derive_more`](https://github.com/JelteF/derive_more) crate is used here
|
|
for better ergonomics. If you don't want to use it, you can manually implement
|
|
`From` for each variant.
|
|
|
|
```rust
|
|
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>
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Optional typed child
|
|
You can also have a single optional child component of a specific type too:
|
|
|
|
```rust
|
|
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 />
|
|
}
|
|
}
|
|
}
|
|
```
|