yew/website/docs/concepts/function-components/hooks/use-reducer.mdx

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`.