Muhammad Hamza f0209c786f
Prepare for Yew 0.20 (#2973)
* 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>
2022-11-25 15:19:07 +05:00

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 />
}
}
}
```