diff --git a/smart-house-web/frontend/src/main.rs b/smart-house-web/frontend/src/main.rs
index 57c11e5..b23fe39 100644
--- a/smart-house-web/frontend/src/main.rs
+++ b/smart-house-web/frontend/src/main.rs
@@ -1,114 +1,89 @@
#![allow(non_snake_case)]
-use leptos::{ev::MouseEvent, prelude::*};
+use leptos::prelude::*;
-// This highlights four different ways that child components can communicate
-// with their parent:
-// 1) : passing a WriteSignal as one of the child component props,
-// for the child component to write into and the parent to read
-// 2) : passing a closure as one of the child component props, for
-// the child component to call
-// 3) : adding an `on:` event listener to a component
-// 4) : providing a context that is used in the component (rather than prop drilling)
-
-#[derive(Copy, Clone)]
-struct SmallcapsContext(WriteSignal);
+// Often, you want to pass some kind of child view to another
+// component. There are two basic patterns for doing this:
+// - "render props": creating a component prop that takes a function
+// that creates a view
+// - the `children` prop: a special property that contains content
+// passed as the children of a component in your view, not as a
+// property
#[component]
pub fn App() -> impl IntoView {
- // just some signals to toggle four classes on our
- let (red, set_red) = signal(false);
- let (right, set_right) = signal(false);
- let (italics, set_italics) = signal(false);
- let (smallcaps, set_smallcaps) = signal(false);
-
- // the newtype pattern isn't *necessary* here but is a good practice
- // it avoids confusion with other possible future `WriteSignal` contexts
- // and makes it easier to refer to it in ButtonD
- provide_context(SmallcapsContext(set_smallcaps));
+ let (items, set_items) = signal(vec![0, 1, 2]);
+ let render_prop = move || {
+ let len = move || items.read().len();
+ view! {
+
"Length: " {len}
+ }
+ };
view! {
-
-
bool, and these signals all implement Fn()
- class:red=red
- class:right=right
- class:italics=italics
- class:smallcaps=smallcaps
- >
- "Lorem ipsum sit dolor amet."
-
-
- // Button A: pass the signal setter
-
-
- // Button B: pass a closure
-
-
- // Button C: use a regular event listener
- // setting an event listener on a component like this applies it
- // to each of the top-level elements the component returns
-
-
- // Button D gets its setter from context rather than props
-
-
- }
-}
-
-/// Button A receives a signal setter and updates the signal itself
-#[component]
-pub fn ButtonA(
- /// Signal that will be toggled when the button is clicked.
- setter: WriteSignal,
-) -> impl IntoView {
- view! {
-
+ // these look just like the children of an HTML element
+
"Here's a child."
+
"Here's another child."
+
+
+ // This component actually iterates over and wraps the children
+
+
"Here's a child."
+
"Here's another child."
+
}
}
-/// Button B receives a closure
+/// Displays a `render_prop` and some children within markup.
#[component]
-pub fn ButtonB(
- /// Callback that will be invoked when the button is clicked.
- on_click: impl FnMut(MouseEvent) + 'static,
-) -> impl IntoView {
+pub fn TakesChildren(
+ /// Takes a function (type F) that returns anything that can be
+ /// converted into a View (type IV)
+ render_prop: F,
+ /// `children` takes the `Children` type
+ /// this is an alias for `Box Fragment>`
+ /// ... aren't you glad we named it `Children` instead?
+ children: Children,
+) -> impl IntoView
+where
+ F: Fn() -> IV,
+ IV: IntoView,
+{
view! {
-
+
""
+
"Render Prop"
+ {render_prop()}
+
+
"Children"
+ {children()}
}
}
-/// Button C is a dummy: it renders a button but doesn't handle
-/// its click. Instead, the parent component adds an event listener.
+/// Wraps each child in an `
` and embeds them in a `
`.
#[component]
-pub fn ButtonC() -> impl IntoView {
- view! {
-
- }
-}
-
-/// Button D is very similar to Button A, but instead of passing the setter as a prop
-/// we get it from the context
-#[component]
-pub fn ButtonD() -> impl IntoView {
- let setter = use_context::().unwrap().0;
+pub fn WrapsChildren(children: ChildrenFragment) -> impl IntoView {
+ // children() returns a `Fragment`, which has a
+ // `nodes` field that contains a Vec
+ // this means we can iterate over the children
+ // to create something new!
+ let children = children()
+ .nodes
+ .into_iter()
+ .map(|child| view! {