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