yew_hooks/hooks/
use_counter.rs

1use std::fmt;
2use std::ops::Deref;
3use std::rc::Rc;
4
5use yew::prelude::*;
6
7enum CounterAction {
8    Increase,
9    IncreaseBy(i32),
10    Decrease,
11    DecreaseBy(i32),
12    Set(i32),
13    Reset,
14}
15
16struct UseCounterReducer {
17    value: i32,
18    default: i32,
19}
20
21impl Reducible for UseCounterReducer {
22    type Action = CounterAction;
23
24    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
25        let next_value = match action {
26            CounterAction::Increase => self.value + 1,
27            CounterAction::IncreaseBy(delta) => self.value + delta,
28            CounterAction::Decrease => self.value - 1,
29            CounterAction::DecreaseBy(delta) => self.value - delta,
30            CounterAction::Set(value) => value,
31            CounterAction::Reset => self.default,
32        };
33
34        Self {
35            value: next_value,
36            default: self.default,
37        }
38        .into()
39    }
40}
41
42impl PartialEq for UseCounterReducer {
43    fn eq(&self, other: &Self) -> bool {
44        self.value == other.value
45    }
46}
47
48/// State handle for the [`use_counter`] hook.
49pub struct UseCounterHandle {
50    inner: UseReducerHandle<UseCounterReducer>,
51}
52
53impl UseCounterHandle {
54    /// Increase by `1`.
55    pub fn increase(&self) {
56        self.inner.dispatch(CounterAction::Increase);
57    }
58
59    /// Increase by `delta`.
60    pub fn increase_by(&self, delta: i32) {
61        self.inner.dispatch(CounterAction::IncreaseBy(delta));
62    }
63
64    /// Decrease by `1`.
65    pub fn decrease(&self) {
66        self.inner.dispatch(CounterAction::Decrease);
67    }
68
69    /// Decrease by `delta`.
70    pub fn decrease_by(&self, delta: i32) {
71        self.inner.dispatch(CounterAction::DecreaseBy(delta));
72    }
73
74    /// Set to `value`.
75    pub fn set(&self, value: i32) {
76        self.inner.dispatch(CounterAction::Set(value));
77    }
78
79    /// Reset to initial value.
80    pub fn reset(&self) {
81        self.inner.dispatch(CounterAction::Reset);
82    }
83}
84
85impl fmt::Debug for UseCounterHandle {
86    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87        f.debug_struct("UseCounterHandle")
88            .field("value", &format!("{:?}", self.inner.value))
89            .field("default", &format!("{:?}", self.inner.default))
90            .finish()
91    }
92}
93
94impl Deref for UseCounterHandle {
95    type Target = i32;
96
97    fn deref(&self) -> &Self::Target {
98        &(*self.inner).value
99    }
100}
101
102impl Clone for UseCounterHandle {
103    fn clone(&self) -> Self {
104        Self {
105            inner: self.inner.clone(),
106        }
107    }
108}
109
110impl PartialEq for UseCounterHandle {
111    fn eq(&self, other: &Self) -> bool {
112        *self.inner == *other.inner
113    }
114}
115
116/// This hook is used to manage counter state in a function component.
117///
118/// # Example
119///
120/// ```rust
121/// # use yew::prelude::*;
122/// #
123/// use yew_hooks::prelude::*;
124///
125/// #[function_component(Counter)]
126/// fn counter() -> Html {
127///     let counter = use_counter(0);
128///
129///     let onincrease = {
130///         let counter = counter.clone();
131///         Callback::from(move |_| counter.increase())
132///     };
133///     let ondecrease = {
134///         let counter = counter.clone();
135///         Callback::from(move |_| counter.decrease())
136///     };
137///     let onincreaseby = {
138///         let counter = counter.clone();
139///         Callback::from(move |_| counter.increase_by(10))
140///     };
141///     let ondecreaseby = {
142///         let counter = counter.clone();
143///         Callback::from(move |_| counter.decrease_by(10))
144///     };
145///     let onset = {
146///         let counter = counter.clone();
147///         Callback::from(move |_| counter.set(100))
148///     };
149///     let onreset = {
150///         let counter = counter.clone();
151///         Callback::from(move |_| counter.reset())
152///     };
153///     
154///     html! {
155///         <div>
156///             <button onclick={onincrease}>{ "Increase" }</button>
157///             <button onclick={ondecrease}>{ "Decrease" }</button>
158///             <button onclick={onincreaseby}>{ "Increase by 10" }</button>
159///             <button onclick={ondecreaseby}>{ "Decrease by 10" }</button>
160///             <button onclick={onset}>{ "Set to 100" }</button>
161///             <button onclick={onreset}>{ "Reset" }</button>
162///             <p>
163///                 <b>{ "Current value: " }</b>
164///                 { *counter }
165///             </p>
166///         </div>
167///     }
168/// }
169/// ```
170#[hook]
171pub fn use_counter(default: i32) -> UseCounterHandle {
172    let inner = use_reducer(move || UseCounterReducer {
173        value: default,
174        default,
175    });
176
177    UseCounterHandle { inner }
178}