Skip to content

Instantly share code, notes, and snippets.

@dmgolembiowski
Created August 3, 2024 11:49
Show Gist options
  • Save dmgolembiowski/9013b44f38792c1c50896398e2b8ec57 to your computer and use it in GitHub Desktop.
Save dmgolembiowski/9013b44f38792c1c50896398e2b8ec57 to your computer and use it in GitHub Desktop.
Leptos Effects update for leptos_0.7
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