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}