diff --git a/packages/hooks/src/computed.rs b/packages/hooks/src/computed.rs index 16e9981e3..248eb4f83 100644 --- a/packages/hooks/src/computed.rs +++ b/packages/hooks/src/computed.rs @@ -8,25 +8,26 @@ use std::{ }; /// Create a new tracked state. -/// Tracked state is state that can drive computed state +/// Tracked state is state that can drive Selector state /// -/// It state will efficiently update any Computed state that is reading from it, but it is not readable on it's own. +/// It state will efficiently update any Selector state that is reading from it, but it is not readable on it's own. /// /// ```rust /// use dioxus::prelude::*; /// /// fn Parent(cx: Scope) -> Element { /// let count = use_tracked_state(cx, || 0); +/// /// render! { /// Child { -/// less_than_five: count.compute(|count| *count < 5), +/// count: count.clone(), /// } /// } /// } /// /// #[inline_props] -/// fn Child(cx: Scope, less_than_five: Computed) -> Element { -/// let less_than_five = less_than_five.use_state(cx); +/// fn Child(cx: Scope, count: Tracked) -> Element { +/// let less_than_five = use_selector(cx, count, |count| *count < 5); /// /// render! { /// "{less_than_five}" @@ -40,14 +41,14 @@ pub fn use_tracked_state(cx: &ScopeState, init: impl FnOnce() -> T) }) } -/// Tracked state is state that can drive computed state +/// Tracked state is state that can drive Selector state /// -/// Tracked state will efficiently update any Computed state that is reading from it, but it is not readable on it's own. +/// Tracked state will efficiently update any Selector state that is reading from it, but it is not readable on it's own. #[derive(Clone)] pub struct Tracked { state: Rc>, update_any: std::sync::Arc, - subscribers: std::rc::Rc>>>, + subscribers: SubscribedCallbacks, } impl PartialEq for Tracked { @@ -67,16 +68,16 @@ impl Tracked { } } - /// Create a new computed state from this tracked state + /// Create a new Selector state from this tracked state pub fn compute( &self, mut compute: impl FnMut(&I) -> O + 'static, - ) -> Computed { + ) -> Selector { let subscribers = Rc::new(RefCell::new(HashSet::new())); let state = Rc::new(RefCell::new(compute(&self.state.borrow()))); let update_any = self.update_any.clone(); - Computed { + Selector { value: state.clone(), subscribers: subscribers.clone(), _tracker: Rc::new(self.track(move |input_state| { @@ -88,7 +89,7 @@ impl Tracked { if different { let mut state = state.borrow_mut(); *state = new; - for id in subscribers.borrow_mut().drain() { + for id in subscribers.borrow().iter().copied() { (update_any)(id); } } @@ -117,7 +118,7 @@ impl Tracked { /// A mutable reference to tracked state pub struct TrackedMut<'a, I> { state: RefMut<'a, I>, - subscribers: std::rc::Rc>>>, + subscribers: SubscribedCallbacks, } impl<'a, I> Deref for TrackedMut<'a, I> { @@ -143,8 +144,10 @@ impl<'a, I> Drop for TrackedMut<'a, I> { } } +type SubscribedCallbacks = std::rc::Rc>>>; + pub(crate) struct Tracker { - subscribers: std::rc::Rc>>>, + subscribers: SubscribedCallbacks, id: usize, } @@ -154,24 +157,33 @@ impl Drop for Tracker { } } -/// Computed state is state that is derived from tracked state -/// -/// Whenever the tracked state changes, the computed state will be updated and any components reading from it will be rerun -#[derive(Clone)] -pub struct Computed { - _tracker: Rc>, - value: Rc>, - subscribers: std::rc::Rc>>, +pub fn use_selector( + cx: &ScopeState, + tracked: &Tracked, + init: impl FnMut(&I) -> O + 'static, +) -> O { + let selector = cx.use_hook(|| tracked.compute(init)); + selector.use_state(cx) } -impl PartialEq for Computed { +/// Selector state is state that is derived from tracked state +/// +/// Whenever the tracked state changes, the Selector state will be updated and any components reading from it will be rerun +#[derive(Clone)] +pub struct Selector { + _tracker: Rc>, + value: Rc>, + subscribers: Rc>>, +} + +impl PartialEq for Selector { fn eq(&self, other: &Self) -> bool { std::rc::Rc::ptr_eq(&self.value, &other.value) } } -impl Computed { - /// Read the computed state and subscribe to updates +impl Selector { + /// Read the Selector state and subscribe to updates pub fn use_state(&self, cx: &ScopeState) -> T { cx.use_hook(|| { let id = cx.scope_id();