Created
August 3, 2024 11:49
-
-
Save dmgolembiowski/9013b44f38792c1c50896398e2b8ec57 to your computer and use it in GitHub Desktop.
Leptos Effects update for leptos_0.7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use leptos::html::Input; | |
use leptos::prelude::*; | |
use leptos::*; | |
use reactive_graph::{ | |
computed::{Memo, *}, | |
effect::Effect, | |
owner::StoredValue, | |
prelude::*, | |
signal::{signal, *}, | |
}; | |
#[derive(Copy, Clone)] | |
struct LogContext(RwSignal<Vec<String>>); | |
#[component] | |
fn App() -> impl IntoView { | |
// Just making a visible log here | |
let log = RwSignal::<Vec<String>>::new(vec![]); | |
let logged = move || log().join("\n"); | |
// the newtype pattern isn't *necessary* here but is a good practice | |
// it avoids confusion with other possible future `RwSignal<Vec<String>>` | |
// contexts and makes it easier to refer to it | |
provide_context(LogContext(log)); | |
view! { | |
<CreateAnEffect/> | |
<pre>{logged}</pre> | |
} | |
} | |
#[component] | |
fn CreateAnEffect() -> impl IntoView { | |
let (first, set_first) = signal(String::new()); | |
let (last, set_last) = signal(String::new()); | |
let (use_last, set_use_last) = signal(true); | |
// this will add the name to the log | |
// any time one of the source signals changes | |
Effect::new(move |_| { | |
log(if use_last() { | |
with!(|first, last| format!("{first} {last}")) | |
} else { | |
first() | |
}) | |
}); | |
view! { | |
<h1>"Effect::new version"</h1> | |
<form> | |
<label> | |
"First Name" | |
<input | |
type="text" | |
name="first" | |
prop:value=first | |
on:change=move |ev| set_first(event_target_value(&ev)) | |
/> | |
</label> | |
<label> | |
"Last Name" | |
<input | |
type="text" | |
name="last" | |
prop:value=last | |
on:change=move |ev| set_last(event_target_value(&ev)) | |
/> | |
</label> | |
<label> | |
"Show Last Name" | |
<input | |
type="checkbox" | |
name="use_last" | |
prop:checked=use_last | |
on:change=move |ev| set_use_last(event_target_checked(&ev)) | |
/> | |
</label> | |
</form> | |
} | |
} | |
#[component] | |
fn ManualVersion() -> impl IntoView { | |
use leptos::html::Input; // or tachys::html::element::Input | |
use reacitve_graph::signal::RwSignal; | |
use tachys::reactive_graph::node_ref::NodeRef; | |
let first = NodeRef::<Input>::new(); | |
let last = NodeRef::<Input>::new(); | |
let use_last = NodeRef::<Input>::new(); | |
let mut prev_name = String::new(); | |
let on_change = move |_| { | |
log(" listener"); | |
let first = first.get().unwrap(); | |
let last = last.get().unwrap(); | |
let use_last = use_last.get().unwrap(); | |
let this_one = if use_last.checked() { | |
format!("{} {}", first.value(), last.value()) | |
} else { | |
first.value() | |
}; | |
if this_one != prev_name { | |
log(&this_one); | |
prev_name = this_one; | |
} | |
}; | |
view! { | |
<h1>"Manual Version"</h1> | |
<form on:change=on_change> | |
<label>"First" <input type="text" name="first" node_ref=first/></label> | |
<label>"Last " <input type="text" name="last" node_ref=last/></label> | |
<label>"Show " <input | |
type="checkbox" | |
name="use_last" | |
checked node_ref=use_last /> | |
</label> | |
</form> | |
} | |
} | |
#[component] | |
fn EffectVsDerivedSignal() -> impl IntoView { | |
let (my_value, set_my_value) = signal(String::new()); | |
// Don't do this. | |
/*let (my_optional_value, set_optional_my_value) | |
= signal(Option::<String>::None); | |
Effect::new(move |_| { | |
if !my_value.get().is_empty() { | |
set_optional_my_value(Some(my_value.get())); | |
} else { | |
set_optional_my_value(None); | |
} | |
});*/ | |
// Do this | |
let my_optional_value = | |
move || (!my_value.with(String::is_empty)).then(|| Some(my_value.get())); | |
view! { | |
<input prop:value=my_value | |
on:input=move |ev| set_my_value(event_target_value(&ev))/> | |
<p>"my_optional_value is " | |
<Show when=move || my_optional_value().is_some() fallback=|| view! { "None" } > | |
"Some(\"" | |
{ my_optional_value().unwrap() } | |
"\")" | |
</Show> | |
</p> | |
} | |
} | |
#[component] | |
pub fn Show<F, W, IV>( | |
// The components Show wraps | |
children: Box<dyn Fn() -> (dyn IntoView + 'static)>, | |
// A closure that returns a bool that determines whether this thing runs | |
when: W, | |
// A closure that returns what gets rendered if the when statement is false | |
fallback: F, | |
) -> impl IntoView | |
where | |
W: Fn() -> bool + 'static, | |
F: Fn() -> IV + 'static, | |
IV: IntoView, | |
{ | |
let memoized_when = Memo::new(move |_| when()); | |
move || match memoized_when.get() { | |
true => children().into_view(), | |
false => fallback().into_view(), | |
} | |
} | |
fn log(msg: impl std::fmt::Display) { | |
let log = use_context::<LogContext>().unwrap().0; | |
log.update(|log| log.push(msg.to_string())); | |
} | |
fn main() { | |
leptos::mount_to_body(App) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment