From 4448f7a83a788567d0f0816ff46ca4d6e8d3fe5e Mon Sep 17 00:00:00 2001 From: Greg Johnston Date: Wed, 19 Oct 2022 07:35:22 -0400 Subject: [PATCH] Example of four modes of parent-child communication between components --- Cargo.toml | 1 + examples/parent-child/Cargo.toml | 14 ++++ examples/parent-child/index.html | 24 ++++++ examples/parent-child/src/lib.rs | 124 ++++++++++++++++++++++++++++++ examples/parent-child/src/main.rs | 7 ++ leptos/src/lib.rs | 2 + 6 files changed, 172 insertions(+) create mode 100644 examples/parent-child/Cargo.toml create mode 100644 examples/parent-child/index.html create mode 100644 examples/parent-child/src/lib.rs create mode 100644 examples/parent-child/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 9aeb174ce..8f3625b0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ exclude = [ "examples/hackernews/hackernews-app", "examples/hackernews/hackernews-client", "examples/hackernews/hackernews-server", + "examples/parent-child", "examples/router", "examples/todomvc", "examples/todomvc-ssr/todomvc-ssr-client", diff --git a/examples/parent-child/Cargo.toml b/examples/parent-child/Cargo.toml new file mode 100644 index 000000000..7ca7cfdf4 --- /dev/null +++ b/examples/parent-child/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "parent-child" +version = "0.1.0" +edition = "2021" + +[dependencies] +leptos = { path = "../../leptos" } +console_log = "0.2" +log = "0.4" + +[profile.release] +codegen-units = 1 +lto = true +opt-level = 'z' \ No newline at end of file diff --git a/examples/parent-child/index.html b/examples/parent-child/index.html new file mode 100644 index 000000000..888f0ba9e --- /dev/null +++ b/examples/parent-child/index.html @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/examples/parent-child/src/lib.rs b/examples/parent-child/src/lib.rs new file mode 100644 index 000000000..fcd9077d9 --- /dev/null +++ b/examples/parent-child/src/lib.rs @@ -0,0 +1,124 @@ +use leptos::*; +use web_sys::Event; + +// 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 a simple event listener on the child component itself +// 4) : providing a context that is used in the component (rather than prop drilling) + +#[derive(Copy, Clone)] +struct SmallcapsContext(WriteSignal); + +#[component] +pub fn App(cx: Scope) -> Element { + // just some signals to toggle three classes on our

+ let (red, set_red) = create_signal(cx, false); + let (right, set_right) = create_signal(cx, false); + let (italics, set_italics) = create_signal(cx, false); + let (smallcaps, set_smallcaps) = create_signal(cx, 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(cx, SmallcapsContext(set_smallcaps)); + + view! { + cx, +

+

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: components that return an Element, like elements, can take on: event handler attributes + + + // 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(cx: Scope, setter: WriteSignal) -> Element { + view! { + cx, + + } +} + +// Button B receives a closure +#[component] +pub fn ButtonB(cx: Scope, on_click: F) -> Element +where + F: Fn(Event) + 'static, +{ + view! { + cx, + + } + + // just a note: in an ordinary function ButtonB could take on_click: impl Fn(Event) + 'static + // and save you from typing out the generic + // the component macro actually expands to define a + // + // struct ButtonBProps where F: Fn(Event) + 'static { + // on_click: F + // } + // + // this is what allows us to have named props in our component invocation, + // instead of an ordered list of function arguments + // if Rust ever had named function arguments we could drop this requirement +} + +// Button C will have its event listener added by the parent +// This is just a way of encapsulating whatever markup you need for the button +#[component] +pub fn ButtonC(cx: Scope) -> Element { + view! { + cx, + + } +} + +// 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(cx: Scope) -> Element { + let setter = use_context::(cx).unwrap().0; + + view! { + cx, + + } +} diff --git a/examples/parent-child/src/main.rs b/examples/parent-child/src/main.rs new file mode 100644 index 000000000..a5dc01fe4 --- /dev/null +++ b/examples/parent-child/src/main.rs @@ -0,0 +1,7 @@ +use leptos::*; +use parent_child::*; + +pub fn main() { + // _ = console_log::init_with_level(log::Level::Debug); + mount_to_body(|cx| view! { cx, }) +} diff --git a/leptos/src/lib.rs b/leptos/src/lib.rs index 2cfc1c709..08cb3165e 100644 --- a/leptos/src/lib.rs +++ b/leptos/src/lib.rs @@ -19,6 +19,8 @@ //! counter example, showing the basics of client-side rendering and reactive DOM updates //! - [`counters`](https://github.com/gbj/leptos/tree/main/examples/counter) introduces parent-child //! communication via contexts, and the `` component for efficient keyed list updates. +//! - [`parent-child`](https://github.com/gbj/leptos/tree/main/examples/parent-child) shows four different +//! ways a parent component can communicate with a child, including passing a closure, context, and more //! - [`todomvc`](https://github.com/gbj/leptos/tree/main/examples/todomvc) implements the classic to-do //! app in Leptos. This is a good example of a complete, simple app. In particular, you might want to //! see how we use [create_effect] to [serialize JSON to `localStorage`](https://github.com/gbj/leptos/blob/16f084a71268ac325fbc4a5e50c260df185eadb6/examples/todomvc/src/lib.rs#L164)