From b316f7ca6990f7a78600f30dd0e9fe3483de38ed Mon Sep 17 00:00:00 2001 From: Noah Date: Fri, 31 Oct 2025 18:09:12 -0700 Subject: [PATCH 1/2] Fix stale selector deps when store doesn't change --- crates/yewdux/src/anymap.rs | 2 +- crates/yewdux/src/functional.rs | 67 +++++++++++++++++---------------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/crates/yewdux/src/anymap.rs b/crates/yewdux/src/anymap.rs index 575b73e..d198021 100644 --- a/crates/yewdux/src/anymap.rs +++ b/crates/yewdux/src/anymap.rs @@ -9,7 +9,7 @@ pub(crate) struct AnyMap { } impl AnyMap { - pub(crate) fn entry(&mut self) -> Entry { + pub(crate) fn entry(&mut self) -> Entry<'_, T> { Entry { map: &mut self.map, _marker: std::marker::PhantomData, diff --git a/crates/yewdux/src/functional.rs b/crates/yewdux/src/functional.rs index 407008a..6550931 100644 --- a/crates/yewdux/src/functional.rs +++ b/crates/yewdux/src/functional.rs @@ -18,7 +18,7 @@ fn use_cx() -> Context { } #[hook] -pub fn use_dispatch() -> Dispatch +pub fn use_dispatch() -> Dispatch where S: Store, { @@ -51,7 +51,7 @@ where /// } /// ``` #[hook] -pub fn use_store() -> (Rc, Dispatch) +pub fn use_store() -> (Rc, Dispatch) where S: Store, { @@ -67,7 +67,7 @@ where /// Simliar to ['use_store'], but only provides the state. #[hook] -pub fn use_store_value() -> Rc +pub fn use_store_value() -> Rc where S: Store, { @@ -174,7 +174,7 @@ where /// Similar to [`use_selector_with_deps`], but also allows an equality function, similar to /// [`use_selector_eq`] #[hook] -pub fn use_selector_eq_with_deps(selector: F, eq: E, deps: D) -> Rc +pub fn use_selector_eq_with_deps(selector: F, is_eq: E, deps: D) -> Rc where S: Store, R: 'static, @@ -183,36 +183,37 @@ where E: Fn(&R, &R) -> bool + 'static, { let dispatch = use_dispatch::(); - // Given to user, this is what we update to force a re-render. - let selected = { - let state = dispatch.get(); - let value = selector(&state, &deps); - - use_state(|| Rc::new(value)) - }; - // Local tracking value, because `selected` isn't updated in our subscriber scope. - let current = { - let value = Rc::clone(&selected); - use_mut_ref(|| value) - }; - - let _dispatch = { - let selected = selected.clone(); - use_memo(deps, move |deps| { - let deps = deps.clone(); - dispatch.subscribe(move |val: Rc| { - let value = selector(&val, &deps); - - if !eq(¤t.borrow(), &value) { - let value = Rc::new(value); - // Update value for user. - selected.set(Rc::clone(&value)); - // Make sure to update our tracking value too. - *current.borrow_mut() = Rc::clone(&value); - } - }) + let store = dispatch.get(); + + // Re-run this hook when the store changes. + let _trigger = use_state(|| ()); + let _sub = use_memo((), move |_| { + dispatch.subscribe_silent(move |_| { + // Trigger a re-render when the store changes. + _trigger.set(()); }) - }; + }); + + // Track if the store has changed. + let store_version = use_state(|| 0u32); + let last_store = use_state(|| Rc::clone(&store)); + if store.should_notify(&last_store) { + last_store.set(Rc::clone(&store)); + store_version.set(1u32.wrapping_add(*store_version)); + } + + // Track if the selected value has changed + let last_selected = use_state(|| None::>); + let selected = use_memo((store_version, deps), move |(_version, deps)| { + let value = Rc::new(selector(&store, &deps)); + match &*last_selected { + Some(last) if is_eq(&value, last) => Rc::clone(last), + _ => { + last_selected.set(Some(Rc::clone(&value))); + value + } + } + }); Rc::clone(&selected) } From fd838e8b19798ed45b8be6de107a2235cf41dc63 Mon Sep 17 00:00:00 2001 From: Noah Date: Tue, 4 Nov 2025 01:08:39 -0800 Subject: [PATCH 2/2] Remove Clone requirements for selector hook deps --- crates/yewdux/src/functional.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/yewdux/src/functional.rs b/crates/yewdux/src/functional.rs index 6550931..4677327 100644 --- a/crates/yewdux/src/functional.rs +++ b/crates/yewdux/src/functional.rs @@ -165,7 +165,7 @@ pub fn use_selector_with_deps(selector: F, deps: D) -> Rc where S: Store, R: PartialEq + 'static, - D: Clone + PartialEq + 'static, + D: PartialEq + 'static, F: Fn(&S, &D) -> R + 'static, { use_selector_eq_with_deps(selector, |a, b| a == b, deps) @@ -178,7 +178,7 @@ pub fn use_selector_eq_with_deps(selector: F, is_eq: E, deps: D) where S: Store, R: 'static, - D: Clone + PartialEq + 'static, + D: PartialEq + 'static, F: Fn(&S, &D) -> R + 'static, E: Fn(&R, &R) -> bool + 'static, {