Skip to content

Commit

Permalink
Merge pull request #296 from Gentle/create_slice
Browse files Browse the repository at this point in the history
create_slice in leptos_reactive
  • Loading branch information
gbj authored Jan 12, 2023
2 parents 3ae0880 + 9180aaa commit 08ec473
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 1 deletion.
2 changes: 2 additions & 0 deletions leptos_reactive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ mod serialization;
mod signal;
mod signal_wrappers_read;
mod signal_wrappers_write;
mod slice;
mod spawn;
mod spawn_microtask;
mod stored_value;
Expand All @@ -98,6 +99,7 @@ pub use serialization::*;
pub use signal::*;
pub use signal_wrappers_read::*;
pub use signal_wrappers_write::*;
pub use slice::*;
pub use spawn::*;
pub use spawn_microtask::*;
pub use stored_value::*;
Expand Down
2 changes: 1 addition & 1 deletion leptos_reactive/src/memo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ use std::fmt::Debug;
)]
pub fn create_memo<T>(cx: Scope, f: impl Fn(Option<&T>) -> T + 'static) -> Memo<T>
where
T: PartialEq + Debug + 'static,
T: PartialEq + 'static,
{
cx.runtime.create_memo(f)
}
Expand Down
76 changes: 76 additions & 0 deletions leptos_reactive/src/slice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use crate::{create_memo, IntoSignalSetter, RwSignal, Scope, Signal, SignalSetter};

/// derives a reactive slice from an [RwSignal](crate::RwSignal)
///
/// Slices have the same guarantees as [Memos](crate::Memo),
/// they only emit their value when it has actually been changed.
///
/// slices need a getter and a setter, and you must make sure that
/// the setter and getter only touch their respective field and nothing else.
/// They optimally should not have any side effects.
///
/// you can use slices whenever you want to react to only parts
/// of a bigger signal, the prime example would be state management
/// where you want all state variables grouped up but also need
/// fine-grained signals for each or some of these variables.
/// In the example below, setting an auth token will only trigger
/// the token signal, but none of the other derived signals.
///
/// ```
/// # use leptos_reactive::*;
/// # let (cx, disposer) = raw_scope_and_disposer(create_runtime());
///
/// // this could be serialized to and from localstorage with miniserde
/// pub struct State {
/// token: String,
/// dark_mode: bool,
/// }
///
/// let state = create_rw_signal(
/// cx,
/// State {
/// token: "".into(),
/// // this would cause flickering on reload,
/// // use a cookie for the initial value in real projects
/// dark_mode: false,
/// },
/// );
/// let (token, set_token) = create_slice(
/// cx,
/// state,
/// |state| state.token.clone(),
/// |state, value| state.token = value,
/// );
/// let (dark_mode, set_dark_mode) = create_slice(
/// cx,
/// state,
/// |state| state.dark_mode,
/// |state, value| state.dark_mode = value,
/// );
/// let count_token_updates = create_rw_signal(cx, 0);
/// count_token_updates.with(|counter| assert_eq!(counter, &0));
/// create_effect(cx, move |_| {
/// token.with(|_| {});
/// count_token_updates.update(|counter| *counter += 1)
/// });
/// count_token_updates.with(|counter| assert_eq!(counter, &1));
/// set_token.set("this is not a token!".into());
/// // token was updated with the new token
/// count_token_updates.with(|counter| assert_eq!(counter, &2));
/// set_dark_mode.set(true);
/// // since token didn't change, there was also no update emitted
/// count_token_updates.with(|counter| assert_eq!(counter, &2));
/// ```
pub fn create_slice<T, O>(
cx: Scope,
signal: RwSignal<T>,
getter: impl Fn(&T) -> O + Clone + Copy + 'static,
setter: impl Fn(&mut T, O) + Clone + Copy + 'static,
) -> (Signal<O>, SignalSetter<O>)
where
O: Eq,
{
let getter = create_memo(cx, move |_| signal.with(getter));
let setter = move |value| signal.update(|x| setter(x, value));
(getter.into(), setter.mapped_signal_setter(cx))
}

0 comments on commit 08ec473

Please sign in to comment.