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