Skip to content

Commit

Permalink
Update documentation around Children (#3297)
Browse files Browse the repository at this point in the history
* Update Children to use Html.

* Fix website.

* Update website/docs/advanced-topics/children.mdx

* add further reading section

---------

Co-authored-by: Muhammad Hamza <[email protected]>
  • Loading branch information
futursolo and ranile authored Aug 5, 2023
1 parent 4daa2ec commit d803df9
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 65 deletions.
69 changes: 66 additions & 3 deletions website/docs/advanced-topics/children.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,31 @@
title: 'Children'
---

:::caution

Inspecting and manipulating `Children` can often result in surprising and hard-to-explain behaviours in your application.
This can lead to edge cases and often does not yield expected result.
You should consider other approaches if you are trying to manipulate `Children`.

Yew supports using `Html` as the type of the children prop.
You should use `Html` as children if you do not need `Children` or `ChildrenRenderer`.
It doesn't have the drawbacks of `Children` and has a lower performance overhead.

:::

## 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};
use yew::{html, Component, Context, Html, Properties};

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

pub struct List;
Expand All @@ -30,7 +42,7 @@ impl Component for List {
fn view(&self, ctx: &Context<Self>) -> Html {
html! {
<div class="list">
{ for ctx.props().children.iter() }
{ctx.props().children.clone()}
</div>
}
}
Expand Down Expand Up @@ -90,6 +102,53 @@ impl Component for List {
}
```

## Nested Children with Props

Nested component properties can be accessed and mutated if the containing component types its children.

```rust
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>
};
```

### Enum typed children

Of course, sometimes you might need to restrict the children to a few different
Expand Down Expand Up @@ -253,3 +312,7 @@ pub fn render_page(with_sidebar: bool) -> Html {
}
}
```

## Further Reading

- For a real-world example of this pattern, check out the yew-router source code. For a more advanced example, check out the [nested-list example](https://github.com/yewstack/yew/tree/master/examples/nested_list) in the main yew repository.
4 changes: 2 additions & 2 deletions website/docs/advanced-topics/portals.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use yew::prelude::*;
#[derive(Properties, PartialEq)]
pub struct ModalProps {
#[prop_or_default]
pub children: Children,
pub children: Html,
}

#[function_component]
Expand All @@ -38,7 +38,7 @@ fn Modal(props: &ModalProps) -> Html {
.expect("Expected to find a #modal_host element");

create_portal(
html!{ {for props.children.iter()} },
props.children.clone(),
modal_host.into(),
)
}
Expand Down
4 changes: 2 additions & 2 deletions website/docs/concepts/contexts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ This situation is called "Prop Drilling".
Consider the following example which passes down the theme using props:

```rust
use yew::{html, Children, Component, Context, Html, Properties, function_component};
use yew::{html, Component, Context, Html, Properties, function_component};

#[derive(Clone, PartialEq)]
pub struct Theme {
Expand Down Expand Up @@ -51,7 +51,7 @@ fn Navbar(props: &NavbarProps) -> Html {
#[derive(PartialEq, Properties)]
pub struct ThemeProps {
theme: Theme,
children: Children,
children: Html,
}

#[function_component]
Expand Down
10 changes: 3 additions & 7 deletions website/docs/concepts/function-components/children.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ title: 'Children'
`Children` is a special prop type that allows you to receive nested `Html` that is provided like html child elements.

```rust
use yew::{function_component, html, Html, Properties, Children};
use yew::{function_component, html, Html, Properties};

#[function_component]
fn App() -> Html {
Expand All @@ -22,20 +22,16 @@ fn App() -> Html {
#[derive(Properties, PartialEq)]
pub struct Props {
// highlight-next-line
pub children: Children, // the field name `children` is important!
pub children: Html, // the field name `children` is important!
}

#[function_component]
fn HelloWorld(props: &Props) -> Html {
html! {
<div class="very-stylized-container">
// highlight-next-line
{ for props.children.iter() } // you can forward children like this
{ props.children.clone() } // you can forward children like this
</div>
}
}
```

## Further reading

- [Advanced ways to handle children](../../advanced-topics/children)
2 changes: 1 addition & 1 deletion website/docs/concepts/html/classes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ struct Props {
#[prop_or_default]
class: Classes,
fill: bool,
children: Children,
children: Html,
}

#[function_component]
Expand Down
53 changes: 3 additions & 50 deletions website/docs/concepts/html/components.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ use yew::prelude::*;
#[derive(PartialEq, Properties)]
struct Props {
id: String,
children: Children,
children: Html,
}

#[function_component]
Expand Down Expand Up @@ -94,7 +94,7 @@ use yew::prelude::*;
#[derive(PartialEq, Properties)]
struct Props {
id: String,
children: Children,
children: Html,
}

#[function_component]
Expand All @@ -108,7 +108,7 @@ fn Container(props: &Props) -> Html {

let props = yew::props!(Props {
id: "container-2",
children: Children::default(),
children: Html::default(),
});

html! {
Expand All @@ -119,53 +119,6 @@ html! {
};
```

## Nested Children with Props

Nested component properties can be accessed and mutated if the containing component types its children. In the following example, the `List` component can wrap `ListItem` components. For a real-world example of this pattern, check out the `yew-router` source code. For a more advanced example, check out the `nested-list` example in the main yew repository.

```rust
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>
};
```

## Relevant examples

- [Function Todo MVC](https://github.com/yewstack/yew/tree/master/examples/function_todomvc)
Expand Down

0 comments on commit d803df9

Please sign in to comment.