yew-hooks 0.2.0

Hooks for the Yew web framework, inspired by react hook libs like streamich/react-use and alibaba/hooks.
Documentation
use std::fmt;
use std::ops::Deref;
use std::rc::Rc;

use yew::prelude::*;

enum CounterAction {
    Increase,
    IncreaseBy(i32),
    Decrease,
    DecreaseBy(i32),
    Set(i32),
    Reset,
}

struct UseCounterReducer {
    value: i32,
    default: i32,
}

impl Reducible for UseCounterReducer {
    type Action = CounterAction;

    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
        let next_value = match action {
            CounterAction::Increase => self.value + 1,
            CounterAction::IncreaseBy(delta) => self.value + delta,
            CounterAction::Decrease => self.value - 1,
            CounterAction::DecreaseBy(delta) => self.value - delta,
            CounterAction::Set(value) => value,
            CounterAction::Reset => self.default,
        };

        Self {
            value: next_value,
            default: self.default,
        }
        .into()
    }
}

impl PartialEq for UseCounterReducer {
    fn eq(&self, other: &Self) -> bool {
        self.value == other.value
    }
}

/// State handle for the [`use_counter`] hook.
pub struct UseCounterHandle {
    inner: UseReducerHandle<UseCounterReducer>,
}

impl UseCounterHandle {
    /// Increase by `1`.
    pub fn increase(&self) {
        self.inner.dispatch(CounterAction::Increase);
    }

    /// Increase by `delta`.
    pub fn increase_by(&self, delta: i32) {
        self.inner.dispatch(CounterAction::IncreaseBy(delta));
    }

    /// Decrease by `1`.
    pub fn decrease(&self) {
        self.inner.dispatch(CounterAction::Decrease);
    }

    /// Decrease by `delta`.
    pub fn decrease_by(&self, delta: i32) {
        self.inner.dispatch(CounterAction::DecreaseBy(delta));
    }

    /// Set to `value`.
    pub fn set(&self, value: i32) {
        self.inner.dispatch(CounterAction::Set(value));
    }

    /// Reset to initial value.
    pub fn reset(&self) {
        self.inner.dispatch(CounterAction::Reset);
    }
}

impl fmt::Debug for UseCounterHandle {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("UseCounterHandle")
            .field("value", &format!("{:?}", self.inner.value))
            .field("default", &format!("{:?}", self.inner.default))
            .finish()
    }
}

impl Deref for UseCounterHandle {
    type Target = i32;

    fn deref(&self) -> &Self::Target {
        &(*self.inner).value
    }
}

impl Clone for UseCounterHandle {
    fn clone(&self) -> Self {
        Self {
            inner: self.inner.clone(),
        }
    }
}

impl PartialEq for UseCounterHandle {
    fn eq(&self, other: &Self) -> bool {
        *self.inner == *other.inner
    }
}

/// This hook is used to manage counter state in a function component.
///
/// # Example
///
/// ```rust
/// # use yew::prelude::*;
/// #
/// use yew_hooks::prelude::*;
///
/// #[function_component(Counter)]
/// fn counter() -> Html {
///     let counter = use_counter(0);
///
///     let onincrease = {
///         let counter = counter.clone();
///         Callback::from(move |_| counter.increase())
///     };
///     let ondecrease = {
///         let counter = counter.clone();
///         Callback::from(move |_| counter.decrease())
///     };
///     let onincreaseby = {
///         let counter = counter.clone();
///         Callback::from(move |_| counter.increase_by(10))
///     };
///     let ondecreaseby = {
///         let counter = counter.clone();
///         Callback::from(move |_| counter.decrease_by(10))
///     };
///     let onset = {
///         let counter = counter.clone();
///         Callback::from(move |_| counter.set(100))
///     };
///     let onreset = {
///         let counter = counter.clone();
///         Callback::from(move |_| counter.reset())
///     };
///     
///     html! {
///         <div>
///             <button onclick={onincrease}>{ "Increase" }</button>
///             <button onclick={ondecrease}>{ "Decrease" }</button>
///             <button onclick={onincreaseby}>{ "Increase by 10" }</button>
///             <button onclick={ondecreaseby}>{ "Decrease by 10" }</button>
///             <button onclick={onset}>{ "Set to 100" }</button>
///             <button onclick={onreset}>{ "Reset" }</button>
///             <p>
///                 <b>{ "Current value: " }</b>
///                 { *counter }
///             </p>
///         </div>
///     }
/// }
/// ```
#[hook]
pub fn use_counter(default: i32) -> UseCounterHandle {
    let inner = use_reducer(move || UseCounterReducer {
        value: default,
        default,
    });

    UseCounterHandle { inner }
}