1use std::fmt;
2use std::ops::Deref;
3use std::rc::Rc;
45use implicit_clone::ImplicitClone;
67use super::{use_reducer, use_reducer_eq, Reducible, UseReducerDispatcher, UseReducerHandle};
8use crate::functional::hook;
9use crate::html::IntoPropValue;
10use crate::Callback;
1112struct UseStateReducer<T> {
13 value: T,
14}
1516impl<T> Reducible for UseStateReducer<T> {
17type Action = T;
1819fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
20 Rc::new(Self { value: action })
21 }
22}
2324impl<T> PartialEq for UseStateReducer<T>
25where
26T: PartialEq,
27{
28fn eq(&self, rhs: &Self) -> bool {
29self.value == rhs.value
30 }
31}
3233/// 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
82T: 'static,
83 F: FnOnce() -> T,
84{
85let handle = use_reducer(move || UseStateReducer { value: init_fn() });
8687 UseStateHandle { inner: handle }
88}
8990/// [`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
96T: PartialEq + 'static,
97 F: FnOnce() -> T,
98{
99let handle = use_reducer_eq(move || UseStateReducer { value: init_fn() });
100101 UseStateHandle { inner: handle }
102}
103104/// State handle for the [`use_state`] hook.
105pub struct UseStateHandle<T> {
106 inner: UseReducerHandle<UseStateReducer<T>>,
107}
108109impl<T: fmt::Debug> fmt::Debug for UseStateHandle<T> {
110fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 f.debug_struct("UseStateHandle")
112 .field("value", &format!("{:?}", self.inner.value))
113 .finish()
114 }
115}
116117impl<T> UseStateHandle<T> {
118/// Replaces the value
119pub fn set(&self, value: T) {
120self.inner.dispatch(value)
121 }
122123/// Returns the setter of current state.
124pub fn setter(&self) -> UseStateSetter<T> {
125 UseStateSetter {
126 inner: self.inner.dispatcher(),
127 }
128 }
129}
130131impl<T> Deref for UseStateHandle<T> {
132type Target = T;
133134fn deref(&self) -> &Self::Target {
135&(*self.inner).value
136 }
137}
138139impl<T> Clone for UseStateHandle<T> {
140fn clone(&self) -> Self {
141Self {
142 inner: self.inner.clone(),
143 }
144 }
145}
146147impl<T> PartialEq for UseStateHandle<T>
148where
149T: PartialEq,
150{
151fn eq(&self, rhs: &Self) -> bool {
152*self.inner == *rhs.inner
153 }
154}
155156impl<T> ImplicitClone for UseStateHandle<T> {}
157158/// Setter handle for [`use_state`] and [`use_state_eq`] hook
159pub struct UseStateSetter<T> {
160 inner: UseReducerDispatcher<UseStateReducer<T>>,
161}
162163impl<T> Clone for UseStateSetter<T> {
164fn clone(&self) -> Self {
165Self {
166 inner: self.inner.clone(),
167 }
168 }
169}
170171impl<T> fmt::Debug for UseStateSetter<T>
172where
173T: fmt::Debug,
174{
175fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 f.debug_struct("UseStateSetter").finish()
177 }
178}
179180impl<T> From<UseStateSetter<T>> for Callback<T> {
181fn from(value: UseStateSetter<T>) -> Self {
182Self::from(value.inner)
183 }
184}
185186impl<T> IntoPropValue<Callback<T>> for UseStateSetter<T> {
187fn into_prop_value(self) -> Callback<T> {
188self.inner.into_prop_value()
189 }
190}
191192impl<T> PartialEq for UseStateSetter<T> {
193fn eq(&self, rhs: &Self) -> bool {
194self.inner == rhs.inner
195 }
196}
197198impl<T> ImplicitClone for UseStateSetter<T> {}
199200impl<T> UseStateSetter<T> {
201/// Replaces the value
202pub fn set(&self, value: T) {
203self.inner.dispatch(value)
204 }
205206/// Get a callback, invoking which is equivalent to calling `set()`
207 /// on this same setter.
208pub fn to_callback(&self) -> Callback<T> {
209self.inner.to_callback()
210 }
211}