1"use strict";(globalThis.webpackChunkyew_docs||=[]).push([[3588],{9459(e,n,t){t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>l,default:()=>p,frontMatter:()=>s,metadata:()=>r,toc:()=>a});const r=JSON.parse('{"id":"advanced-topics/children","title":"Children","description":"Inspecting and manipulating Children can often result in surprising and hard-to-explain behaviours in your application.","source":"@site/versioned_docs/version-0.23/advanced-topics/children.mdx","sourceDirName":"advanced-topics","slug":"/advanced-topics/children","permalink":"/docs/advanced-topics/children","draft":false,"unlisted":false,"editUrl":"https://github.com/yewstack/yew/blob/master/website/versioned_docs/version-0.23/advanced-topics/children.mdx","tags":[],"version":"0.23","frontMatter":{"title":"Children"},"sidebar":"docs","previous":{"title":"Refs","permalink":"/docs/advanced-topics/struct-components/refs"},"next":{"title":"Optimizations","permalink":"/docs/advanced-topics/optimizations"}}');var i=t(74848),o=t(28453);const s={title:"Children"},l=void 0,d={},a=[{value:"General usage",id:"general-usage",level:2},{value:"Advanced usage",id:"advanced-usage",level:2},{value:"Typed children",id:"typed-children",level:3},{value:"Nested Children with Props",id:"nested-children-with-props",level:2},{value:"Enum typed children",id:"enum-typed-children",level:3},{value:"Optional typed child",id:"optional-typed-child",level:3},{value:"Further Reading",id:"further-reading",level:2}];function c(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(n.admonition,{type:"caution",children:[(0,i.jsxs)(n.p,{children:["Inspecting and manipulating ",(0,i.jsx)(n.code,{children:"Children"})," can often result in surprising and hard-to-explain behaviours in your application.\nThis can lead to edge cases and often does not yield expected result.\nYou should consider other approaches if you are trying to manipulate ",(0,i.jsx)(n.code,{children:"Children"}),"."]}),(0,i.jsxs)(n.p,{children:["Yew supports using ",(0,i.jsx)(n.code,{children:"Html"})," as the type of the children prop.\nYou should use ",(0,i.jsx)(n.code,{children:"Html"})," as children if you do not need ",(0,i.jsx)(n.code,{children:"Children"})," or ",(0,i.jsx)(n.code,{children:"ChildrenRenderer"}),".\nIt doesn't have the drawbacks of ",(0,i.jsx)(n.code,{children:"Children"})," and has a lower performance overhead."]})]}),"\n",(0,i.jsx)(n.h2,{id:"general-usage",children:"General usage"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.em,{children:"Most of the time,"})," when allowing a component to have children, you don't care\nwhat type of children the component has. In such cases, the below example will\nsuffice."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-rust",children:'use yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n #[prop_or_default]\n pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n type Message = ();\n type Properties = ListProps;\n\n fn create(_ctx: &Context<Self>) -> Self {\n Self\n }\n\n fn view(&self, ctx: &Context<Self>) -> Html {\n html! {\n <div class="list">\n {ctx.props().children.clone()}\n </div>\n }\n }\n}\n'})}),"\n",(0,i.jsx)(n.h2,{id:"advanced-usage",children:"Advanced usage"}),"\n",(0,i.jsx)(n.h3,{id:"typed-children",children:"Typed children"}),"\n",(0,i.jsxs)(n.p,{children:["In cases where you want one type of component to be passed as children to your component,\nyou can use ",(0,i.jsx)(n.code,{children:"yew::html::ChildrenWithProps<T>"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-rust",children:'use yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n type Message = ();\n type Properties = ();\n\n fn create(_ctx: &Context<Self>) -> Self {\n Self\n }\n\n fn view(&self, _ctx: &Context<Self>) -> Html {\n html! {\n { "item" }\n }\n }\n}
1\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n #[prop_or_default]\n pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n type Message = ();\n type Properties = ListProps;\n\n fn create(_ctx: &Context<Self>) -> Self {\n Self\n }\n\n fn view(&self, ctx: &Context<Self>) -> Html {\n html! {\n <div class="list">\n { for ctx.props().children.iter() }\n </div>\n }\n }\n}\n'})}),"\n",(0,i.jsx)(n.h2,{id:"nested-children-with-props",children:"Nested Children with Props"}),"\n",(0,i.jsx)(n.p,{children:"Nested component properties can be accessed and mutated if the containing component types its children."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-rust",children:'use std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n value: String,\n}\n\n#[component]\nfn ListItem(props: &ListItemProps) -> Html {\n let ListItemProps { value } = props.clone();\n html! {\n <span>\n {value}\n </span>\n }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n pub children: ChildrenWithProps<ListItem>,\n}\n\n#[component]\nfn List(props: &Props) -> Html {\n let modified_children = props.children.iter().map(|mut item| {\n let mut props = Rc::make_mut(&mut item.props);\n props.value = format!("item-{}", props.value);\n item\n });\n html! {{for modified_children}}\n}\n\nhtml! {\n <List>\n <ListItem value="a" />\n <ListItem value="b" />\n <ListItem value="c" />\n </List>\n};\n'})}),"\n",(0,i.jsx)(n.h3,{id:"enum-typed-children",children:"Enum typed children"}),"\n",(0,i.jsx)(n.p,{children:"Of course, sometimes you might need to restrict the children to a few different\ncomponents. In these cases, you have to get a little more hands-on with Yew."}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.a,{href:"https://github.com/JelteF/derive_more",children:(0,i.jsx)(n.code,{children:"derive_more"})})," crate is used here\nfor better ergonomics. If you don't want to use it, you can manually implement\n",(0,i.jsx)(n.code,{children:"From"})," for each variant."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-rust",children:'use yew::{\n html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n type Message = ();\n type Properties = ();\n\n fn create(_ctx: &Context<Self>) -> Self {\n Self\n }\n\n fn view(&self, _ctx: &Context<Self>) -> Html {\n html! {\n { "Primary" }\n }\n }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n type Message = ();\n type Properties = ();\n\n fn create(_ctx: &Context<Self>) -> Self {\n Self\n }\n\n fn view(&self, _ctx: &Context<Self>) -> Html {\n html! {\n { "Secondary" }\n }\n }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n Primary(VChild<Primary>),\n Secondary(VChild<Secondary>),\n}\n\n// Now, we implement `Into<Html>` so that yew knows how to render `Item`.\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n fn into(self) -> Html {\n match self {\n Self::Primary(child) => child.into(),\n Self::Secondary(child) => child.into(),\n }\n }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n #[prop_or_default]\n pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n type Message = ();\n type Properties = ListProps;\n\n fn create(_ctx: &Context<Self>) -> Self {\n Self\n }\n\n fn view(&self, ctx: &Context<Self>) -> Html {\n html! {\n <div class="list">\n { for ctx.props().children.iter() }\n </div>\n }\n }\n}\n'})}),"\n",(0,i.jsx)(n.h3,{id:"optional-typed-child",children:"Optional typed child"}),"\n",(0,i.jsx)(n.p,{children:"You can also have a single optional child component of a specific type too:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-rust",children:'use yew::{\n html, html_nested, virtual_dom::VChild, Component,\n Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n type Message = ();\n type Properties = ();\n\n fn create(_ctx: &Context<Self>) -> Self {\n Self\n }\n\n fn view(&self, _ctx: &Context<Self>) -> Html {\n html! {\n { "sidebar" }\n }\n }\n}
1\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n #[prop_or_default]\n pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n type Message = ();\n type Properties = PageProps;\n\n fn create(_ctx: &Context<Self>) -> Self {\n Self\n }\n\n fn view(&self, ctx: &Context<Self>) -> Html {\n html! {\n <div class="page">\n { ctx.props().sidebar.clone() }\n // ... page content\n </div>\n }\n }\n}\n\n// The page component can be called either with the sidebar or without:\n\npub fn render_page(with_sidebar: bool) -> Html {\n if with_sidebar {\n // Page with sidebar\n html! {\n <Page sidebar={html_nested! {\n <PageSideBar />\n }} />\n }\n } else {\n // Page without sidebar\n html! {\n <Page />\n }\n }\n}\n'})}),"\n",(0,i.jsx)(n.h2,{id:"further-reading",children:"Further Reading"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["For a real-world example of this pattern, check out the yew-router source code. For a more advanced example, check out the ",(0,i.jsx)(n.a,{href:"https://github.com/yewstack/yew/tree/master/examples/nested_list",children:"nested-list example"})," in the main yew repository."]}),"\n"]})]})}function p(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},28453(e,n,t){t.d(n,{R:()=>s,x:()=>l});var r=t(96540);const i={},o=r.createContext(i);function s(e){const n=r.useContext(o);return r.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),r.createElement(o.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.