Skip to main content
This is unreleased documentation for Yew Next version.
For up-to-date documentation, see the latest version on docs.rs.

yew/functional/hooks/
use_state.rs

1use std::fmt;
2use std::mem::transmute;
3use std::ops::Deref;
4use std::rc::Rc;
5
6use implicit_clone::ImplicitClone;
7
8use super::{use_reducer, use_reducer_eq, Reducible, UseReducerDispatcher, UseReducerHandle};
9use crate::functional::hook;
10use crate::html::IntoPropValue;
11use crate::Callback;
12
13#[repr(transparent)]
14struct UseStateReducer<T> {
15    value: T,
16}
17
18impl<T> Reducible for UseStateReducer<T> {
19    type Action = T;
20
21    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
22        Rc::new(Self { value: action })
23    }
24}
25
26impl<T> PartialEq for UseStateReducer<T>
27where
28    T: PartialEq,
29{
30    fn eq(&self, rhs: &Self) -> bool {
31        self.value == rhs.value
32    }
33}
34
35/// This hook is used to manage state in a function component.
36///
37/// This hook will always trigger a re-render upon receiving a new state. See [`use_state_eq`]
38/// if you want the component to only re-render when the new state compares unequal
39/// to the existing one.
40///
41/// # Example
42///
43/// ```rust
44/// use yew::prelude::*;
45/// # use std::rc::Rc;
46///
47/// #[component(UseState)]
48/// fn state() -> Html {
49///     let counter = use_state(|| 0);
50///     let onclick = {
51///         let counter = counter.clone();
52///         Callback::from(move |_| counter.set(*counter + 1))
53///     };
54///
55///     html! {
56///         <div>
57///             <button {onclick}>{ "Increment value" }</button>
58///             <p>
59///                 <b>{ "Current value: " }</b>
60///                 { *counter }
61///             </p>
62///         </div>
63///     }
64/// }
65/// ```
66///
67/// # Caution
68///
69/// The value held in the handle will reflect the value of at the time the
70/// handle is returned by the `use_state()` call. It is possible that the handle does
71/// not dereference to an up to date value, for example if you are moving it into a
72/// `use_effect_with` hook. You can register the
73/// state to the dependents so the hook can be updated when the value changes.
74///
75/// # Tip
76///
77/// The setter function is guaranteed to be the same across the entire
78/// component lifecycle. You can safely omit the `UseStateHandle` from the
79/// dependents of `use_effect_with` if you only intend to set
80/// values from within the hook.
81#[hook]
82pub fn use_state<T, F>(init_fn: F) -> UseStateHandle<T>
83where
84    T: 'static,
85    F: FnOnce() -> T,
86{
87    let handle = use_reducer(move || UseStateReducer { value: init_fn() });
88
89    UseStateHandle { inner: handle }
90}
91
92/// [`use_state`] but only re-renders when `prev_state != next_state`.
93///
94/// This hook requires the state to implement [`PartialEq`].
95#[hook]
96pub fn use_state_eq<T, F>(init_fn: F) -> UseStateHandle<T>
97where
98    T: PartialEq + 'static,
99    F: FnOnce() -> T,
100{
101    let handle = use_reducer_eq(move || UseStateReducer { value: init_fn() });
102
103    UseStateHandle { inner: handle }
104}
105
106/// State handle for the [`use_state`] hook.
107pub struct UseStateHandle<T> {
108    inner: UseReducerHandle<UseStateReducer<T>>,
109}
110
111impl<T: fmt::Debug> fmt::Debug for UseStateHandle<T> {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        f.debug_struct("UseStateHandle")
114            .field("value", &format!("{:?}", **self))
115            .finish_non_exhaustive()
116    }
117}
118
119impl<T> UseStateHandle<T> {
120    /// Returns the current value of the handle as an `Rc`.
121    ///
122    /// Unlike [`Deref`], this gives you an owned `Rc<T>` that can be moved
123    /// into closures or stored without borrowing the handle.
124    pub fn value_rc(&self) -> Rc<T> {
125        // SAFETY: `UseStateReducer<T>` is `repr(transparent)` over `T`, so
126        // `Rc<UseStateReducer<T>>` and `Rc<T>` have identical layouts.
127        unsafe { transmute::<Rc<UseStateReducer<T>>, Rc<T>>(self.inner.value_rc()) }
128    }
129
130    /// Replaces the value
131    pub fn set(&self, value: T) {
132        self.inner.dispatch(value)
133    }
134
135    /// Returns the setter of current state.
136    pub fn setter(&self) -> UseStateSetter<T> {
137        UseStateSetter {
138            inner: self.inner.dispatcher(),
139        }
140    }
141
142    /// Destructures the handle into its two parts: the current value as an
143    /// `Rc<T>`, and the setter for updating the state.
144    pub fn into_inner(self) -> (Rc<T>, UseStateSetter<T>) {
145        let (data, inner) = self.inner.into_inner();
146        // SAFETY: same repr(transparent) guarantee as `value_rc`.
147        (
148            unsafe { transmute::<Rc<UseStateReducer<T>>, Rc<T>>(data) },
149            UseStateSetter { inner },
150        )
151    }
152}
153
154impl<T> Deref for UseStateHandle<T> {
155    type Target = T;
156
157    fn deref(&self) -> &Self::Target {
158        &self.inner.value
159    }
160}
161
162impl<T> Clone for UseStateHandle<T> {
163    fn clone(&self) -> Self {
164        Self {
165            inner: self.inner.clone(),
166        }
167    }
168}
169
170impl<T> PartialEq for UseStateHandle<T>
171where
172    T: PartialEq,
173{
174    fn eq(&self, rhs: &Self) -> bool {
175        self.inner == rhs.inner
176    }
177}
178
179impl<T> ImplicitClone for UseStateHandle<T> {}
180
181/// Setter handle for [`use_state`] and [`use_state_eq`] hook
182pub struct UseStateSetter<T> {
183    inner: UseReducerDispatcher<UseStateReducer<T>>,
184}
185
186impl<T> Clone for UseStateSetter<T> {
187    fn clone(&self) -> Self {
188        Self {
189            inner: self.inner.clone(),
190        }
191    }
192}
193
194impl<T> fmt::Debug for UseStateSetter<T>
195where
196    T: fmt::Debug,
197{
198    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199        f.debug_struct("UseStateSetter").finish_non_exhaustive()
200    }
201}
202
203impl<T> From<UseStateSetter<T>> for Callback<T> {
204    fn from(value: UseStateSetter<T>) -> Self {
205        Self::from(value.inner)
206    }
207}
208
209impl<T> IntoPropValue<Callback<T>> for UseStateSetter<T> {
210    fn into_prop_value(self) -> Callback<T> {
211        self.inner.into_prop_value()
212    }
213}
214
215impl<T> PartialEq for UseStateSetter<T> {
216    fn eq(&self, rhs: &Self) -> bool {
217        self.inner == rhs.inner
218    }
219}
220
221impl<T> ImplicitClone for UseStateSetter<T> {}
222
223impl<T> UseStateSetter<T> {
224    /// Replaces the value
225    pub fn set(&self, value: T) {
226        self.inner.dispatch(value)
227    }
228
229    /// Get a callback, invoking which is equivalent to calling `set()`
230    /// on this same setter.
231    pub fn to_callback(&self) -> Callback<T> {
232        self.inner.to_callback()
233    }
234}