diff --git a/packages/sycamore-reactive/src/signal.rs b/packages/sycamore-reactive/src/signal.rs index 81c29c4d..be254b23 100644 --- a/packages/sycamore-reactive/src/signal.rs +++ b/packages/sycamore-reactive/src/signal.rs @@ -228,6 +228,25 @@ impl Signal { self.trigger_subscribers(); } + /// Set the value of the state using a function that receives the current value. + /// + /// This will notify and update any effects and memos that depend on this value. + /// + /// # Example + /// ``` + /// # use sycamore_reactive::*; + /// # create_scope_immediate(|cx| { + /// let state = create_signal(cx, 0); + /// assert_eq!(*state.get(), 0); + /// + /// state.set_fn(|n| n + 1); + /// assert_eq!(*state.get(), 1); + /// # }); + /// ``` + pub fn set_fn T>(&self, f: F) { + self.set(f(&self.get_untracked())); + } + /// Set the current value of the state wrapped in a [`Rc`]. Unlike [`Signal::set()`], this /// method accepts the value wrapped in a [`Rc`] because the underlying storage is already using /// [`Rc`], thus preventing an unnecessary clone. @@ -258,6 +277,13 @@ impl Signal { self.set_rc_silent(Rc::new(value)); } + /// Set the value of the state using a function that receives the current value _without_ triggering subscribers. + /// + /// Make sure you know what you are doing because this can make state inconsistent. + pub fn set_fn_silent T>(&self, f: F) { + self.set_silent(f(&self.get_untracked())); + } + /// Set the current value of the state wrapped in a [`Rc`] _without_ triggering subscribers. /// /// See the documentation for [`Signal::set_rc()`] for more information. @@ -636,6 +662,9 @@ mod tests { state.set(1); assert_eq!(*state.get(), 1); + + state.set_fn(|n| n + 1); + assert_eq!(*state.get(), 2); }); } @@ -660,6 +689,9 @@ mod tests { assert_eq!(*double.get(), 0); state.set_silent(1); assert_eq!(*double.get(), 0); // double value is unchanged. + + state.set_fn_silent(|n| n + 1); + assert_eq!(*double.get(), 0); // double value is unchanged. }); }