mirror of
https://github.com/yewstack/yew.git
synced 2025-12-08 21:26:25 +00:00
* 0.20 Changelog * Improve changelog generator * Add blog post * Add blog post * Apply suggestions from code review Co-authored-by: WorldSEnder <WorldSEnder@users.noreply.github.com> Co-authored-by: Julius Lungys <32368314+voidpumpkin@users.noreply.github.com> * update Changelog * update Cargo.toml * changelog gen compiles * website version 0.20 * add migration guides * prettier * i18n Co-authored-by: WorldSEnder <WorldSEnder@users.noreply.github.com> Co-authored-by: Julius Lungys <32368314+voidpumpkin@users.noreply.github.com>
256 lines
5.0 KiB
Plaintext
256 lines
5.0 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 />
|
|
}
|
|
}
|
|
}
|
|
```
|