yew_hooks/hooks/
use_latest.rs

1use std::cell::RefCell;
2use std::rc::Rc;
3
4use yew::prelude::*;
5
6/// State handle for the [`use_mut_latest`] hook.
7pub struct UseMutLatestHandle<T> {
8    inner: Rc<RefCell<Rc<RefCell<T>>>>,
9}
10
11impl<T> UseMutLatestHandle<T> {
12    /// Get the latest mutable ref to state or props.
13    pub fn current(&self) -> Rc<RefCell<T>> {
14        self.inner.borrow().clone()
15    }
16}
17
18impl<T> Clone for UseMutLatestHandle<T> {
19    fn clone(&self) -> Self {
20        Self {
21            inner: self.inner.clone(),
22        }
23    }
24}
25
26impl<T> PartialEq for UseMutLatestHandle<T>
27where
28    T: PartialEq,
29{
30    fn eq(&self, other: &Self) -> bool {
31        *self.inner == *other.inner
32    }
33}
34
35/// State handle for the [`use_latest`] hook.
36pub struct UseLatestHandle<T> {
37    inner: Rc<RefCell<Rc<T>>>,
38}
39
40impl<T> UseLatestHandle<T> {
41    /// Get the latest immutable ref to state or props.
42    pub fn current(&self) -> Rc<T> {
43        self.inner.borrow().clone()
44    }
45}
46
47impl<T> Clone for UseLatestHandle<T> {
48    fn clone(&self) -> Self {
49        Self {
50            inner: self.inner.clone(),
51        }
52    }
53}
54
55impl<T> PartialEq for UseLatestHandle<T>
56where
57    T: PartialEq,
58{
59    fn eq(&self, other: &Self) -> bool {
60        *self.inner == *other.inner
61    }
62}
63
64/// This hook returns the latest mutable ref to state or props.
65///
66/// # Example
67///
68/// ```rust
69/// # use gloo::timers::callback::Interval;
70/// # use yew::prelude::*;
71/// #
72/// use yew_hooks::prelude::*;
73///
74/// #[function_component(UseMutLatest)]
75/// fn mut_latest() -> Html {
76///     let state = use_state(|| 0);
77///     let interval = use_mut_ref(|| None);
78///     let closure = {
79///         let state = state.clone();
80///         move || state.set(*state + 1)
81///     };
82///
83///     let latest_closure = use_mut_latest(closure);
84///
85///     use_effect_with((), move |_| {
86///         *interval.borrow_mut() = Some(Interval::new(1000, move || {
87///             let latest_closure = latest_closure.current();
88///             let closure = &*latest_closure.borrow_mut();
89///             // This will get the latest closure and increase state by 1 each time.
90///             closure();
91///         }));
92///         move || *interval.borrow_mut() = None
93///     });
94///     
95///     html! {
96///         <div>
97///             <p>
98///                 <b>{ "Latest value: " }</b>
99///                 { *state }
100///             </p>
101///         </div>
102///     }
103/// }
104/// ```
105#[hook]
106pub fn use_mut_latest<T>(value: T) -> UseMutLatestHandle<T>
107where
108    T: 'static,
109{
110    let value_rc = Rc::new(RefCell::new(value));
111    let inner = use_mut_ref(|| value_rc.clone());
112
113    // Update the ref each render so if it changes the newest value will be saved.
114    *inner.borrow_mut() = value_rc;
115
116    UseMutLatestHandle { inner }
117}
118
119/// This hook returns the latest immutable ref to state or props.
120///
121/// # Example
122///
123/// ```rust
124/// # use gloo::timers::callback::Interval;
125/// # use yew::prelude::*;
126/// #
127/// use yew_hooks::prelude::*;
128///
129/// #[function_component(UseLatest)]
130/// fn latest() -> Html {
131///     let state = use_state(|| 0);
132///     let interval = use_mut_ref(|| None);
133///
134///     let latest_state = use_latest(state.clone());
135///
136///     {
137///         let state = state.clone();
138///         use_effect_with((), move |_| {
139///             *interval.borrow_mut() = Some(Interval::new(1000, move || {
140///                 // This will get the latest state and increase it by 1 each time.
141///                 state.set(**latest_state.current() + 1);
142///             }));
143///             move || *interval.borrow_mut() = None
144///         });
145///     }
146///     
147///     html! {
148///         <div>
149///             <p>
150///                 <b>{ "Latest value: " }</b>
151///                 { *state }
152///             </p>
153///         </div>
154///     }
155/// }
156/// ```
157#[hook]
158pub fn use_latest<T>(value: T) -> UseLatestHandle<T>
159where
160    T: 'static,
161{
162    let value_rc = Rc::new(value);
163    let inner = use_mut_ref(|| value_rc.clone());
164
165    // Update the ref each render so if it changes the newest value will be saved.
166    *inner.borrow_mut() = value_rc;
167
168    UseLatestHandle { inner }
169}