mirror of https://github.com/yewstack/yew
110 lines
3.1 KiB
Plaintext
110 lines
3.1 KiB
Plaintext
---
|
|
title: "use_reducer"
|
|
---
|
|
|
|
`use_reducer` is an alternative to [`use_state`](./use-state). It is used to handle more complex component's state.
|
|
|
|
It accepts an initial state function and returns a `UseReducerHandle` that dereferences to the state,
|
|
and a dispatch function.
|
|
The dispatch function takes one argument of type `Action`. When called, the action and current value
|
|
are passed to the reducer function which computes a new state that is returned,
|
|
and the component is re-rendered.
|
|
|
|
:::tip Advanced tip
|
|
|
|
The dispatch function is guaranteed to be the same across the entire
|
|
component lifecycle. You can safely omit the `UseReducerHandle` from the
|
|
dependents of `use_effect_with_deps` if you only intend to dispatch
|
|
values from within the hooks.
|
|
|
|
:::
|
|
|
|
The state object returned by the initial state function is required to
|
|
implement a `Reducible` trait which provides an `Action` type and a
|
|
reducer function.
|
|
|
|
This hook will always trigger a re-render upon receiving an action. See
|
|
[`use_reducer_eq`](#use_reducer_eq) if you want the component to only
|
|
re-render when the state changes.
|
|
|
|
## Example
|
|
|
|
```rust
|
|
use yew::prelude::*;
|
|
use std::rc::Rc;
|
|
|
|
/// reducer's Action
|
|
enum CounterAction {
|
|
Double,
|
|
Square,
|
|
}
|
|
|
|
/// reducer's State
|
|
struct CounterState {
|
|
counter: i32,
|
|
}
|
|
|
|
impl Default for CounterState {
|
|
fn default() -> Self {
|
|
Self { counter: 1 }
|
|
}
|
|
}
|
|
|
|
impl Reducible for CounterState {
|
|
/// Reducer Action Type
|
|
type Action = CounterAction;
|
|
|
|
/// Reducer Function
|
|
fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
|
|
let next_ctr = match action {
|
|
CounterAction::Double => self.counter * 2,
|
|
CounterAction::Square => self.counter.pow(2)
|
|
};
|
|
|
|
Self { counter: next_ctr }.into()
|
|
}
|
|
}
|
|
|
|
#[function_component]
|
|
fn ReducerExample() -> Html {
|
|
// The use_reducer hook takes an initialization function which will be called only once.
|
|
let counter = use_reducer(CounterState::default);
|
|
|
|
let double_onclick = {
|
|
let counter = counter.clone();
|
|
Callback::from(move |_| counter.dispatch(CounterAction::Double))
|
|
};
|
|
let square_onclick = {
|
|
let counter = counter.clone();
|
|
Callback::from(move |_| counter.dispatch(CounterAction::Square))
|
|
};
|
|
|
|
html! {
|
|
<>
|
|
<div id="result">{ counter.counter }</div>
|
|
|
|
<button onclick={double_onclick}>{ "Double" }</button>
|
|
<button onclick={square_onclick}>{ "Square" }</button>
|
|
</>
|
|
}
|
|
}
|
|
```
|
|
|
|
:::caution
|
|
|
|
The value held in the handle will reflect the value of at the time the
|
|
handle is returned by the `use_reducer`. It is possible that the handle does
|
|
not dereference to an up to date value if you are moving it into a
|
|
`use_effect_with_deps` hook. You can register the
|
|
state to the dependents so the hook can be updated when the value changes.
|
|
|
|
:::
|
|
|
|
## `use_reducer_eq`
|
|
|
|
This hook has the same effect as `use_reducer` but will only trigger a
|
|
re-render when the reducer function produces a value that `prev_state != next_state`.
|
|
|
|
This hook requires the state object to implement `PartialEq` in addition
|
|
to the `Reducible` trait required by `use_reducer`.
|