diff --git a/smart-house-web/frontend/src/main.rs b/smart-house-web/frontend/src/main.rs index 50fccde..be163b3 100644 --- a/smart-house-web/frontend/src/main.rs +++ b/smart-house-web/frontend/src/main.rs @@ -1,159 +1,100 @@ #![allow(non_snake_case)] +use leptos::ev::SubmitEvent; use leptos::prelude::*; -// Iteration is a very common task in most applications. -// So how do you take a list of data and render it in the DOM? -// This example will show you the two ways: -// 1) for mostly-static lists, using Rust iterators -// 2) for lists that grow, shrink, or move items, using - #[component] fn App() -> impl IntoView { view! { -

"Iteration"

-

"Static List"

-

"Use this pattern if the list itself is static."

- -

"Dynamic List"

-

"Use this pattern if the rows in your list will change."

- +

"Controlled Component"

+ +

"Uncontrolled Component"

+ } } -/// A list of counters, without the ability -/// to add or remove any. #[component] -fn StaticList( - /// How many counters to include in this list. - length: usize, -) -> impl IntoView { - // create counter signals that start at incrementing numbers - let counters = (1..=length).map(|idx| RwSignal::new(idx)); +fn ControlledComponent() -> impl IntoView { + // create a signal to hold the value + let (name, set_name) = signal("Controlled".to_string()); - // when you have a list that doesn't change, you can - // manipulate it using ordinary Rust iterators - // and collect it into a Vec<_> to insert it into the DOM - let counter_buttons = counters - .map(|count| { - view! { -
  • - -
  • - } - }) - .collect::>(); - - // Note that if `counter_buttons` were a reactive list - // and its value changed, this would be very inefficient: - // it would rerender every row every time the list changed. view! { -
      {counter_buttons}
    + +

    "Name is: " {name}

    } } -/// A list of counters that allows you to add or -/// remove counters. #[component] -fn DynamicList( - /// The number of counters to begin with. - initial_length: usize, -) -> impl IntoView { - // This dynamic list will use the component. - // is a keyed list. This means that each row - // has a defined key. If the key does not change, the row - // will not be re-rendered. When the list changes, only - // the minimum number of changes will be made to the DOM. +fn UncontrolledComponent() -> impl IntoView { + // import the type for + use leptos::html::Input; - // `next_counter_id` will let us generate unique IDs - // we do this by simply incrementing the ID by one - // each time we create a counter - let mut next_counter_id = initial_length; + let (name, set_name) = signal("Uncontrolled".to_string()); - // we generate an initial list as in - // but this time we include the ID along with the signal - // see NOTE in add_counter below re: ArcRwSignal - let initial_counters = (0..initial_length) - .map(|id| (id, ArcRwSignal::new(id + 1))) - .collect::>(); + // we'll use a NodeRef to store a reference to the input element + // this will be filled when the element is created + let input_element: NodeRef = NodeRef::new(); - // now we store that initial list in a signal - // this way, we'll be able to modify the list over time, - // adding and removing counters, and it will change reactively - let (counters, set_counters) = signal(initial_counters); + // fires when the form `submit` event happens + // this will store the value of the in our signal + let on_submit = move |ev: SubmitEvent| { + // stop the page from reloading! + ev.prevent_default(); - let add_counter = move |_| { - // create a signal for the new counter - // we use ArcRwSignal here, instead of RwSignal - // ArcRwSignal is a reference-counted type, rather than the arena-allocated - // signal types we've been using so far. - // When we're creating a collection of signals like this, using ArcRwSignal - // allows each signal to be deallocated when its row is removed. - let sig = ArcRwSignal::new(next_counter_id + 1); - // add this counter to the list of counters - set_counters.update(move |counters| { - // since `.update()` gives us `&mut T` - // we can just use normal Vec methods like `push` - counters.push((next_counter_id, sig)) - }); - // increment the ID so it's always unique - next_counter_id += 1; + // here, we'll extract the value from the input + let value = input_element + .get() + // event handlers can only fire after the view + // is mounted to the DOM, so the `NodeRef` will be `Some` + .expect(" to exist") + // `NodeRef` implements `Deref` for the DOM element type + // this means we can call`HtmlInputElement::value()` + // to get the current value of the input + .value(); + set_name.set(value); }; view! { -
    - -
      - // The component is central here - // This allows for efficient, key list rendering - instead of - each=move || counters.get() - // the key should be unique and stable for each row - // using an index is usually a bad idea, unless your list - // can only grow, because moving items around inside the list - // means their indices will change and they will all rerender - key=|counter| counter.0 - // `children` receives each item from your `each` iterator - // and returns a view - children=move |(id, count)| { - // we can convert our ArcRwSignal to a Copy-able RwSignal - // for nicer DX when moving it into the view - let count = RwSignal::from(count); - view! { -
    • - - -
    • - } - } - /> -
    -
    +
    + + +
    +

    "Name is: " {name}

    } } +// This `main` function is the entry point into the app +// It just mounts our component to the +// Because we defined it as `fn App`, we can now use it in a +// template as fn main() { leptos::mount::mount_to_body(App) }