Derived State
Derived state allows you to create state that automatically reacts to changes in another store. This is useful for:
- Computing derived values from your primary state
- Creating focused views of larger state objects
- Building dependent state relationships
Defining Derived State
There are two ways to create derived state:
- Using the
Store
macro withderived_from
orderived_from_mut
attributes - Manually implementing the
Store
trait and callingderived_from
orderived_from_mut
Using the Store Macro
The simplest approach is to use the Store
derive macro with the derived_from
or derived_from_mut
attributes:
#![allow(unused)] fn main() { use std::rc::Rc; use yewdux::prelude::*; // Original source state #[derive(Default, Clone, PartialEq, Store)] struct Count { count: u32, } // Immutable derived state - creates a new instance on change #[derive(Default, Clone, PartialEq, Store)] #[store(derived_from(Count))] struct CountMultiplied { value: u32, } impl DerivedFrom<Count> for CountMultiplied { fn on_change(&self, state: Rc<Count>) -> Self { Self { value: state.count * 10, } } } // Mutable derived state - updates in place #[derive(Default, Clone, PartialEq, Store)] #[store(derived_from_mut(Count))] struct CountIsEven { status: bool, } impl DerivedFromMut<Count> for CountIsEven { fn on_change(&mut self, state: Rc<Count>) { self.status = state.count % 2 == 0; } } }
Manual Implementation
For more control, you can implement Store
manually and register the relationship in your new
method:
#![allow(unused)] fn main() { #[derive(Default, Clone, PartialEq)] struct CountIsEven { status: bool, } impl DerivedFromMut<Count> for CountIsEven { fn on_change(&mut self, state: Rc<Count>) { self.status = state.count % 2 == 0; } } impl Store for CountIsEven { fn new(cx: &yewdux::Context) -> Self { // Register this state as derived from `Count` cx.derived_from_mut::<Count, Self>(); // Initialize with current Count value let status = cx.get::<Count>().count % 2 == 0; Self { status } } fn should_notify(&self, old: &Self) -> bool { self != old } } }
Using Derived State
Using derived state is identical to using any other store:
#![allow(unused)] fn main() { #[function_component] fn App() -> Html { let (count, dispatch) = use_store::<Count>(); let is_even = use_store_value::<CountIsEven>(); let multiplied = use_store_value::<CountMultiplied>(); let onclick = dispatch.reduce_mut_callback(|state| state.count += 1); html! { <> <p>{"Count: "}{ count.count }</p> <p>{"Is Even: "}{ is_even.status.to_string() }</p> <p>{"Multiplied by 10: "}{ multiplied.value }</p> <button {onclick}>{"+1"}</button> </> } } }
How It Works
When you use derived_from
or derived_from_mut
:
- A listener is registered that watches for changes in the source state
- When the source state changes, your
on_change
implementation is called - Your derived state is updated either by creating a new instance (
DerivedFrom
) or by modifying it in place (DerivedFromMut
) - Components using the derived state are re-rendered
This provides a clean, type-safe way to create computed or dependent state without manual synchronization.