Listeners
Listeners are component-less subscribers. They are used to describe side-effects that should happen
whenever state changes. They live for application lifetime, and are created with init_listener
.
Here's a simple listener that logs the current state whenever it changes.
#![allow(unused)] fn main() { extern crate yew; extern crate yewdux; use yew::prelude::*; use std::rc::Rc; use yewdux::prelude::*; #[derive(Default, Clone, PartialEq, Debug, Store)] struct State { count: u32, } struct StateLogger; impl Listener for StateLogger { // Here's where we define which store we are listening to. type Store = State; // Here's where we decide what happens when `State` changes. fn on_change(&self, _cx: &yewdux::Context, state: Rc<Self::Store>) { yewdux::log::info!("state changed: {:?}", state); } } }
Can can start the listener by calling init_listener
somewhere in our code. A good place to put it is
the store constructor.
NOTE: Successive calls to init_listener
on the same type will do nothing.
#![allow(unused)] fn main() { extern crate yewdux; use std::rc::Rc; use yewdux::prelude::*; #[derive(Default, PartialEq, Debug)] struct State { count: u32, } struct StateLogger; impl Listener for StateLogger { // Here's where we say which store we want to subscribe to. type Store = State; fn on_change(&self, _cx: &yewdux::Context, state: Rc<Self::Store>) { yewdux::log::info!("state changed: {:?}", state); } } impl Store for State { fn new(cx: &yewdux::Context) -> Self { init_listener(|| StateLogger, cx); Default::default() } fn should_notify(&self, other: &Self) -> bool { self != other } } }
Tracking state
Sometimes it's useful to keep track of how a store has been changing over time. However this should
not be done in the listener itself. Notice Listener::on_change
takes an immutable reference. This
is necessary because otherwise we start to run into borrowing issues when listeners are triggered
recursively.
To track changes we can instead use a separate store that listens to the store we want to track.
#![allow(unused)] fn main() { extern crate yewdux; use std::rc::Rc; use yewdux::prelude::*; #[derive(Default, PartialEq, Debug)] struct State { count: u32, } #[derive(Default, PartialEq, Debug, Store, Clone)] struct ChangeTracker { count: u32, } struct ChangeTrackerListener; impl Listener for StateLogger { type Store = State; fn on_change(&self, cx: &yewdux::Context, state: Rc<Self::Store>) { let dispatch = Dispatch::<ChangeTracker>::new(cx); dipatch.reduce_mut(|state| state.count += 1); let count = dispatch.get().count; println!("State has changed {} times", count); } } impl Store for State { fn new(cx: &yewdux::Context) -> Self { init_listener(|| ChangeTrackerListener, cx); Default::default() } fn should_notify(&self, other: &Self) -> bool { self != other } } }