### Running Yewdux Examples with Trunk Source: https://intendednull.github.io/yewdux/example.html Instructions on how to run complete Yewdux examples. Requires Trunk, a Rust WASM bundler. Replace '[example]' with the desired example name. ```bash trunk serve examples/[example]/index.html --open ``` -------------------------------- ### Yewdux Root Component Setup Source: https://intendednull.github.io/yewdux/ssr.html Demonstrates how to set up YewduxRoot to manage shared application state. YewduxRoot must be placed above all components that utilize stores. ```rust extern crate yew; extern crate yewdux; use yew::prelude::*; use yewdux::prelude::*; #[derive(Default, Clone, PartialEq, Eq, Store)] struct State { count: u32, } #[function_component] fn Counter() -> Html { let (state, dispatch) = use_store::(); let onclick = dispatch.reduce_mut_callback(|state| state.count += 1); html! { <>

{ state.count }

} } #[function_component] fn App() -> Html { // YewduxRoot must be kept above all components that use any of your stores. html! { } } ``` -------------------------------- ### Initialize Store with Context Source: https://intendednull.github.io/yewdux/print.html Set the initial store value dynamically before the application starts or within a component lifecycle. ```rust extern crate yewdux; use yewdux::prelude::*; #[derive(PartialEq, Store, Default)] struct MyStore { foo: String, bar: String, } fn main() { // Construct foo and bar however necessary let foo = "foo".to_string(); let bar = "bar".to_string(); // Run this before starting your app. Dispatch::::global().set(MyStore { foo, bar }); // ... continue with your app setup } ``` ```rust #![allow(unused)] fn main() { extern crate yew; extern crate yewdux; use yewdux::prelude::*; use yew::prelude::*; #[derive(PartialEq, Store, Default)] struct MyStore { foo: String, bar: String, } #[function_component] fn MyComponent() -> Html { let dispatch = use_dispatch::(); // This runs only once, on the first render of the component. use_effect_with( (), // empty deps move |_| { // Construct foo and bar however necessary let foo = "foo".to_string(); let bar = "bar".to_string(); dispatch.set(MyStore { foo, bar }); || {} }, ); html! { // Your component html } } } ``` -------------------------------- ### Yewdux Counter Example Source: https://intendednull.github.io/yewdux/example.html Demonstrates reading and writing to shared state using Yewdux. Includes state definition, a view component to display the count, and an increment component to modify the state. ```rust #![allow(unused)] fn main() { extern crate yewdux; extern crate yew; use yew::prelude::*; use yewdux::prelude::*; #[derive(Default, Clone, PartialEq, Store)] struct State { count: u32, } #[function_component] fn ViewCount() -> Html { let (state, _) = use_store::(); html!(state.count) } #[function_component] fn IncrementCount() -> Html { let (_, dispatch) = use_store::(); let onclick = dispatch.reduce_mut_callback(|counter| counter.count += 1); html! { } } #[function_component] fn App() -> Html { html! { <> } } } ``` -------------------------------- ### Yewdux Component with Struct Support Source: https://intendednull.github.io/yewdux/ssr.html Illustrates using Yewdux with struct components via a higher-order component pattern. This example shows how to subscribe to state changes and dispatch actions within a component. ```rust extern crate yew; extern crate yewdux; use std::rc::Rc; use yew::prelude::*; use yewdux::prelude::*; #[derive(Default, Clone, PartialEq, Eq, Store)] struct State { count: u32, } #[derive(Properties, Clone, PartialEq)] struct Props { dispatch: Dispatch, } enum Msg { StateChanged(Rc), } struct MyComponent { state: Rc, dispatch: Dispatch, } impl Component for MyComponent { type Properties = Props; type Message = Msg; fn create(ctx: &Context) -> Self { let callback = ctx.link().callback(Msg::StateChanged); let dispatch = ctx.props().dispatch.clone().subscribe_silent(callback); Self { state: dispatch.get(), dispatch, } } fn update(&mut self, _ctx: &Context, msg: Self::Message) -> bool { match msg { Msg::StateChanged(state) => { self.state = state; true } } } fn view(&self, ctx: &Context) -> Html { let count = self.state.count; let onclick = self.dispatch.reduce_mut_callback(|s| s.count += 1); html! { <>

{ count }

} } } #[function_component] fn MyComponentHoc() -> Html { let dispatch = use_dispatch::(); html! { } } #[function_component] fn App() -> Html { // YewduxRoot must be kept above all components that use any of your stores. html! { } } ``` -------------------------------- ### Struct Component with Dispatch and Subscription Source: https://intendednull.github.io/yewdux/print.html For struct components, use the `Dispatch` type and its `subscribe_silent` method to manage state. This example demonstrates manual state updates within the component. ```rust #![allow(unused)] fn main() { extern crate yew; extern crate yewdux; use std::rc::Rc; use yew::prelude::*; use yewdux::prelude::*; #[derive(Default, Clone, PartialEq, Eq, Store)] struct State { count: u32, } #[derive(Properties, Clone, PartialEq)] struct Props { dispatch: Dispatch, } enum Msg { StateChanged(Rc), } struct MyComponent { state: Rc, dispatch: Dispatch, } impl Component for MyComponent { type Properties = Props; type Message = Msg; fn create(ctx: &Context) -> Self { let callback = ctx.link().callback(Msg::StateChanged); let dispatch = ctx.props().dispatch.clone().subscribe_silent(callback); Self { state: dispatch.get(), dispatch, } } fn update(&mut self, _ctx: &Context, msg: Self::Message) -> bool { match msg { Msg::StateChanged(state) => { self.state = state; true } } } fn view(&self, ctx: &Context) -> Html { let count = self.state.count; let onclick = self.dispatch.reduce_mut_callback(|s| s.count += 1); html! { <>

{ count }

} } } #[function_component] fn MyComponentHoc() -> Html { let dispatch = use_dispatch::(); html! { } } #[function_component] fn App() -> Html { // YewduxRoot must be kept above all components that use any of your stores. html! { } } } ``` -------------------------------- ### Add Custom Listener for State Changes Source: https://intendednull.github.io/yewdux/persistence.html Inject custom listeners into the `#[store]` macro to perform actions when the state changes. The `LogListener` example logs the new count value to the console. ```rust #![allow(unused)] fn main() { extern crate yewdux; extern crate serde; use std::rc::Rc; use yewdux::prelude::*; use serde::{Serialize, Deserialize}; #[derive(Default, Clone, PartialEq, Eq, Deserialize, Serialize, Store)] #[store(storage = "local", listener(LogListener))] struct State { count: u32, } struct LogListener; impl Listener for LogListener { type Store = State; fn on_change(&mut self, _cx: &yewdux::Context, state: Rc) { yewdux::log::info!("Count changed to {}", state.count); } } } ``` -------------------------------- ### Handle Asynchronous State Updates Source: https://intendednull.github.io/yewdux/print.html Supports futures natively for asynchronous operations without additional setup. ```rust #![allow(unused)] fn main() { extern crate yewdux; extern crate yew; use std::rc::Rc; use yewdux::prelude::*; use yew::prelude::*; #[derive(PartialEq, Store)] struct User { name: Option>, } async fn get_user() -> User { User { name: Some("bob".into()) } } let dispatch = Dispatch::::global(); // Use yew::platform::spawn_local to run a future. let future = async move { let user = get_user().await; dispatch.set(user); }; } ``` -------------------------------- ### Get Current State with Dispatch Source: https://intendednull.github.io/yewdux/reading.html Use `Dispatch::get` to read the current state immediately. Note that this method does not provide change detection, so components will not re-render automatically when state changes. ```rust #![allow(unused)] fn main() { extern crate yewdux; use std::rc::Rc; use yewdux::prelude::*; #[derive(PartialEq, Default, Store)] struct State { count: u32, } // Create a dispatch from the global context. This works for non-global contexts too, we would just // pass in the context we want. let dispatch = Dispatch::::global(); let state: Rc = dispatch.get(); } ``` -------------------------------- ### Create Local Yewdux Context Source: https://intendednull.github.io/yewdux/context.html Demonstrates how to create a new local context and a dispatch for managing a locally scoped store. Use this when you need isolated state management. ```rust extern crate yew; extern crate yewdux; use yew::prelude::*; use yewdux::prelude::*; #[derive(Clone, PartialEq, Default, Store)] struct Counter(u32); let cx = yewdux::Context::new(); let dispatch = Dispatch::::new(&cx); ``` -------------------------------- ### Persist State with Local Storage Source: https://intendednull.github.io/yewdux/persistence.html Use the `#[store]` macro with `storage = "local"` to persist application state in the browser's local storage. Ensure `serde` is included for serialization. ```rust #![allow(unused)] fn main() { extern crate yewdux; extern crate serde; use yewdux::prelude::*; use serde::{Serialize, Deserialize}; #[derive(Default, PartialEq, Serialize, Deserialize, Store)] #[store(storage = "local")] // can also be "session" struct State { count: u32, } } ``` -------------------------------- ### Demonstrate Context Isolation Source: https://intendednull.github.io/yewdux/print.html Verify that state changes in one context do not affect stores in another context. ```rust #![allow(unused)] fn main() { extern crate yewdux; use yewdux::prelude::*; #[derive(Clone, PartialEq, Default, Store)] struct Counter(u32); let cx_1 = yewdux::Context::new(); let dispatch_1 = Dispatch::::new(&cx_1); let cx_2 = yewdux::Context::new(); let dispatch_2 = Dispatch::::new(&cx_2); dispatch_1.set(Counter(1)); dispatch_2.set(Counter(2)); assert!(dispatch_1.get() != dispatch_2.get()); } ``` -------------------------------- ### Dispatching State Updates Source: https://intendednull.github.io/yewdux/dispatch.html Demonstrates various methods to update the store's state using a dispatch instance: setting a new state directly, reducing state based on the previous value, and creating a callback for UI events. ```rust extern crate yewdux; extern crate yew; use yewdux::prelude::*; use yew::prelude::*; #[derive(Default, PartialEq, Store)] struct State { count: u32, } // Create a global dispatch let dispatch = Dispatch::::global(); // Set the value immediately dispatch.set(State { count: 0 }); // Set the value immediately based on the last value dispatch.reduce(|state| State { count: state.count + 1}.into()); // Create a callback to set the value when a button is clicked let onclick = dispatch.reduce_callback(|state| State { count: state.count + 1}.into()); html! { }; ``` -------------------------------- ### Implement Store Manually Source: https://intendednull.github.io/yewdux/store.html Define a Store manually to gain fine-grained control over initialization and component notification logic. ```rust #![allow(unused)] fn main() { extern crate yewdux; use yewdux::prelude::*; #[derive(PartialEq)] struct State { count: u32, } impl Store for State { fn new(_cx: &yewdux::Context) -> Self { Self { count: Default::default(), } } fn should_notify(&self, old: &Self) -> bool { // When this returns true, all components are notified and consequently re-render. self != old } } } ``` -------------------------------- ### Set Initial Store State Globally Source: https://intendednull.github.io/yewdux/default_store.html Use Dispatch::global().set to initialize store state before the application renders. ```rust extern crate yewdux; use yewdux::prelude::*; #[derive(PartialEq, Store, Default)] struct MyStore { foo: String, bar: String, } fn main() { // Construct foo and bar however necessary let foo = "foo".to_string(); let bar = "bar".to_string(); // Run this before starting your app. Dispatch::::global().set(MyStore { foo, bar }); // ... continue with your app setup } ``` -------------------------------- ### Configure Store Attributes Source: https://intendednull.github.io/yewdux/store.html Customize Store behavior using attributes like storage persistence, tab synchronization, and derived state relationships. ```rust #![allow(unused)] fn main() { #[derive(Default, PartialEq, Store)] #[store(storage = "local")] // Enable local storage persistence #[store(storage_tab_sync = true)] // Enable tab synchronization #[store(listener(MyCustomListener))] // Register custom listeners #[store(derived_from(OtherStore))] // Create derived state (immutable) #[store(derived_from_mut(OtherStore))] // Create derived state (mutable) struct State { count: u32, } } ``` -------------------------------- ### Initialize a Listener in a Store Source: https://intendednull.github.io/yewdux/listeners.html Register a listener within the Store constructor using init_listener. Successive calls to init_listener on the same type will do nothing. ```rust #![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) { 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 } } } ``` -------------------------------- ### Initialize Store State in Function Component Source: https://intendednull.github.io/yewdux/default_store.html Use the use_effect_with hook with empty dependencies to set initial store state on the first component render. ```rust #![allow(unused)] fn main() { extern crate yew; extern crate yewdux; use yewdux::prelude::*; use yew::prelude::*; #[derive(PartialEq, Store, Default)] struct MyStore { foo: String, bar: String, } #[function_component] fn MyComponent() -> Html { let dispatch = use_dispatch::(); // This runs only once, on the first render of the component. use_effect_with( (), // empty deps move |_| { // Construct foo and bar however necessary let foo = "foo".to_string(); let bar = "bar".to_string(); dispatch.set(MyStore { foo, bar }); || {} }, ); html! { // Your component html } } } ``` -------------------------------- ### Implement Derived State with Macros Source: https://intendednull.github.io/yewdux/print.html Use the Store derive macro with derived_from or derived_from_mut attributes to automatically synchronize state changes. ```rust #![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 for CountMultiplied { fn on_change(&self, state: Rc) -> 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 for CountIsEven { fn on_change(&mut self, state: Rc) { self.status = state.count % 2 == 0; } } } ``` -------------------------------- ### Sync State Across Tabs with Local Storage Source: https://intendednull.github.io/yewdux/persistence.html To synchronize state changes across multiple tabs of the same application, add `storage_tab_sync` to the `#[store]` macro. This ensures all open tabs reflect the latest state. ```rust #![allow(unused)] fn main() { extern crate yewdux; extern crate serde; use yewdux::prelude::*; use serde::{Serialize, Deserialize}; #[derive(Default, Clone, PartialEq, Eq, Deserialize, Serialize, Store)] #[store(storage = "local", storage_tab_sync)] struct State { count: u32, } } ``` -------------------------------- ### Handling Asynchronous State Updates with Dispatch Source: https://intendednull.github.io/yewdux/dispatch.html Yewdux supports asynchronous operations natively. Use `yew::platform::spawn_local` to run futures that update the store's state. ```rust extern crate yewdux; extern crate yew; use std::rc::Rc; use yewdux::prelude::*; use yew::prelude::*; #[derive(Default, PartialEq, Store)] struct User { name: Option>, } async fn get_user() -> User { User { name: Some("bob".into()) } } let dispatch = Dispatch::::global(); // Use yew::platform::spawn_local to run a future. let future = async move { let user = get_user().await; dispatch.set(user); }; ``` -------------------------------- ### Add Yewdux dependency to Cargo.toml Source: https://intendednull.github.io/yewdux/setup.html Use these configurations in your Cargo.toml file to include Yewdux and the required Yew CSR feature. ```toml [dependencies] yew = { version = "0.23", features = ["csr"] } yewdux = "0.13" ``` ```toml [dependencies] yew = { version = "0.23", features = ["csr"] } yewdux = { git = "https://github.com/intendednull/yewdux.git" } ``` -------------------------------- ### Creating a Global Dispatch Source: https://intendednull.github.io/yewdux/dispatch.html Create a global dispatch instance for a specific store type. This is suitable for WASM targets and provides access to state management from anywhere in your Rust code. ```rust extern crate yewdux; use yewdux::prelude::*; #[derive(Default, PartialEq, Store)] struct State { count: u32, } let dispatch = Dispatch::::global(); ``` -------------------------------- ### Define Derived State with Store Macro Source: https://intendednull.github.io/yewdux/derived_state.html Use the `Store` derive macro with `derived_from` or `derived_from_mut` for immutable or mutable derived state, respectively. The `on_change` implementation defines how the derived state is computed from the source state. ```rust #![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 for CountMultiplied { fn on_change(&self, state: Rc) -> 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 for CountIsEven { fn on_change(&mut self, state: Rc) { self.status = state.count % 2 == 0; } } } ``` -------------------------------- ### Implement Store with Derive Macro Source: https://intendednull.github.io/yewdux/store.html Use the Store derive macro to automatically implement the Store trait for a state struct. ```rust #![allow(unused)] fn main() { extern crate yewdux; use yewdux::prelude::*; #[derive(Default, PartialEq, Store)] struct State { count: u32, } } ``` -------------------------------- ### Track State Changes with a Secondary Store Source: https://intendednull.github.io/yewdux/listeners.html Use a separate store to track changes to another store, avoiding borrowing issues by using Dispatch to update state. ```rust #![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) { let dispatch = Dispatch::::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 } } } ``` -------------------------------- ### Global Context in Yewdux (WASM) Source: https://intendednull.github.io/yewdux/context.html Shows how to access the global context, which is thread-local and effectively accessible everywhere in WASM. This is the standard way to manage application-wide state. ```rust extern crate yewdux; use yewdux::prelude::*; #[derive(Clone, PartialEq, Default, Store)] struct Counter(u32); // These are equivalent! let dispatch_1 = Dispatch::::global(); let dispatch_2 = Dispatch::::new(&yewdux::Context::global()); dispatch_1.set(Counter(1)); assert!(dispatch_1.get() == dispatch_2.get()); ``` -------------------------------- ### Manual Subscription for Struct Components Source: https://intendednull.github.io/yewdux/reading.html For struct components, manual subscription is required, offering finer control at the cost of boilerplate. Ensure you retain the dispatch instance; dropping it will unsubscribe and prevent state change notifications. ```rust #![allow(unused)] fn main() { extern crate yewdux; extern crate yew; use std::rc::Rc; use yew::prelude::*; use yewdux::prelude::*; #[derive(PartialEq, Default, Clone, Store)] struct State { count: u32, } struct MyComponent { dispatch: Dispatch, state: Rc, } enum Msg { StateChanged(Rc), } impl Component for MyComponent { type Properties = (); type Message = Msg; fn create(ctx: &Context) -> Self { // The callback for receiving updates to state. let callback = ctx.link().callback(Msg::StateChanged); // Subscribe to changes in state. New state is received in `update`. Be sure to save this, // dropping it will unsubscribe. let dispatch = Dispatch::::global().subscribe_silent(callback); Self { // Get the current state. state: dispatch.get(), dispatch, } } fn update(&mut self, ctx: &Context, msg: Msg) -> bool { match msg { // Receive new state. Msg::StateChanged(state) => { self.state = state; // Only re-render this component if count is greater that 0 (for this example). if self.state.count > 0 { true } else { false } } } } fn view(&self, ctx: &Context) -> Html { let count = self.state.count; let onclick = self.dispatch.reduce_mut_callback(|s| s.count += 1); html! { <>

{ count }

} } } } ``` -------------------------------- ### Manually Implement Derived State Source: https://intendednull.github.io/yewdux/derived_state.html For more control, manually implement the `Store` trait and register the derived state relationship in the `new` method using `cx.derived_from_mut` or `cx.derived_from`. Ensure `should_notify` is implemented correctly. ```rust #![allow(unused)] fn main() { #[derive(Default, Clone, PartialEq)] struct CountIsEven { status: bool, } impl DerivedFromMut for CountIsEven { fn on_change(&mut self, state: Rc) { 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::(); // Initialize with current Count value let status = cx.get::().count % 2 == 0; Self { status } } fn should_notify(&self, old: &Self) -> bool { self != old } } } ``` -------------------------------- ### Predictable State Mutation with apply and apply_callback Source: https://intendednull.github.io/yewdux/dispatch.html Implement predictable state mutations by defining messages and applying them using the `apply` or `apply_callback` methods. This approach is useful for complex state transitions. ```rust extern crate yewdux; extern crate yew; use std::rc::Rc; use yew::prelude::*; use yewdux::prelude::*; #[derive(Default, PartialEq, Clone, Store)] struct State { count: u32, } enum Msg { AddOne, } impl Reducer for Msg { fn apply(self, state: Rc) -> Rc { match self { Msg::AddOne => State { count: state.count + 1 }.into(), } } } let dispatch = Dispatch::::global(); dispatch.apply(Msg::AddOne); let onclick = dispatch.apply_callback(|_| Msg::AddOne); html! { }; ``` -------------------------------- ### Use Selector with Dependencies in Yewdux Source: https://intendednull.github.io/yewdux/reading.html Use `use_selector_with_deps` when your selector needs to capture variables from its environment. Provide these variables as dependencies to ensure the selector updates correctly. For multiple dependencies, use a tuple. ```rust #![allow(unused)] fn main() { extern crate yewdux; extern crate yew; use std::collections::HashMap; use yewdux::prelude::*; use yew::prelude::*; #[derive(Default, Clone, PartialEq, Store)] struct Items { inner: HashMap, } #[derive(Clone, PartialEq, Properties)] struct DisplayItemProps { item_id: u32, } #[function_component] fn DisplayItem(props: &DisplayItemProps) -> Html { // For multiple dependencies, try using a tuple: (dep1, dep2, ..) let item = use_selector_with_deps( |state: &Items, item_id| state.inner.get(item_id).cloned(), props.item_id, ); // Only render the item if it exists. let item = match item.as_ref() { Some(item) => item, None => return Default::default(), }; html! {

{ item }

} } } ``` -------------------------------- ### Implement Default for Yewdux Store Source: https://intendednull.github.io/yewdux/default_store.html Manually implement the Default trait to define the default value of a store. ```rust #![allow(unused)] fn main() { extern crate yewdux; use yewdux::prelude::*; #[derive(PartialEq, Store)] struct MyStore { foo: String, bar: String, } impl Default for MyStore { fn default() -> Self { Self { foo: "foo".to_string(), bar: "bar".to_string(), } } } } ``` -------------------------------- ### Use Copy-on-Write with Rc::make_mut Source: https://intendednull.github.io/yewdux/print.html Utilizes Rc::make_mut within a Reducer implementation for efficient state updates. ```rust #![allow(unused)] fn main() { extern crate yewdux; use std::rc::Rc; use yewdux::prelude::*; #[derive(Default, PartialEq, Clone, Store)] struct State { count: u32, } enum Msg { AddOne, } impl Reducer for Msg { fn apply(self, mut state: Rc) -> Rc { let state_mut = Rc::make_mut(&mut state); match self { Msg::AddOne => state_mut.count += 1, }; state } } } ``` -------------------------------- ### Local Context Isolation in Yewdux Source: https://intendednull.github.io/yewdux/context.html Illustrates that changes to one local context do not affect others. Each context provides an independent state. This is useful for ensuring state encapsulation. ```rust extern crate yewdux; use yewdux::prelude::*; #[derive(Clone, PartialEq, Default, Store)] struct Counter(u32); let cx_1 = yewdux::Context::new(); let dispatch_1 = Dispatch::::new(&cx_1); let cx_2 = yewdux::Context::new(); let dispatch_2 = Dispatch::::new(&cx_2); dispatch_1.set(Counter(1)); dispatch_2.set(Counter(2)); assert!(dispatch_1.get() != dispatch_2.get()); ``` -------------------------------- ### Manual State Subscription for Struct Components Source: https://intendednull.github.io/yewdux/print.html Manually subscribe to state changes in a struct component. Ensure the dispatch instance is stored to prevent the subscription from being dropped. ```rust #![allow(unused)] fn main() { extern crate yewdux; extern crate yew; use std::rc::Rc; use yew::prelude::*; use yewdux::prelude::*; #[derive(PartialEq, Default, Clone, Store)] struct State { count: u32, } struct MyComponent { dispatch: Dispatch, state: Rc, } enum Msg { StateChanged(Rc), } impl Component for MyComponent { type Properties = (); type Message = Msg; fn create(ctx: &Context) -> Self { // The callback for receiving updates to state. let callback = ctx.link().callback(Msg::StateChanged); // Subscribe to changes in state. New state is received in `update`. Be sure to save this, // dropping it will unsubscribe. let dispatch = Dispatch::::global().subscribe_silent(callback); Self { // Get the current state. state: dispatch.get(), dispatch, } } fn update(&mut self, ctx: &Context, msg: Msg) -> bool { match msg { // Receive new state. Msg::StateChanged(state) => { self.state = state; // Only re-render this component if count is greater that 0 (for this example). if self.state.count > 0 { true } else { false } } } } fn view(&self, ctx: &Context) -> Html { let count = self.state.count; let onclick = self.dispatch.reduce_mut_callback(|s| s.count += 1); html! { <>

{ count }

} } } } ``` -------------------------------- ### Use Store Hook for Automatic Re-renders Source: https://intendednull.github.io/yewdux/reading.html The `use_store` hook automatically subscribes to your store and re-renders the component when state changes. This hook must be called at the top level of a function component. ```rust #![allow(unused)] fn main() { extern crate yewdux; extern crate yew; use yewdux::prelude::*; use yew::prelude::*; #[derive(PartialEq, Default, Store)] struct State { count: u32, } #[function_component] fn ViewCount() -> Html { let (state, dispatch) = use_store::(); html!(state.count) } } ``` -------------------------------- ### Create Global Dispatch Source: https://intendednull.github.io/yewdux/print.html Initialize a global dispatch for state access outside of Yew components, restricted to wasm targets. ```rust #![allow(unused)] fn main() { extern crate yewdux; use yewdux::prelude::*; #[derive(Default, PartialEq, Store)] struct State { count: u32, } let dispatch = Dispatch::::global(); } ``` -------------------------------- ### Mutating State with reduce_mut and reduce_mut_callback Source: https://intendednull.github.io/yewdux/dispatch.html Utilize `_mut` variants for state mutation, which require the `Store` to implement `Clone`. This method offers less boilerplate for direct state modifications. ```rust extern crate yewdux; extern crate yew; use yewdux::prelude::*; use yew::prelude::*; #[derive(Default, PartialEq, Clone, Store)] struct State { count: u32, } // Create a global dispatch let dispatch = Dispatch::::global(); // Mutate the current value dispatch.reduce_mut(|state| state.count += 1); // Create a callback to mutate the value when a button is clicked let onclick = dispatch.reduce_mut_callback(|counter| counter.count += 1); html! { }; ``` -------------------------------- ### Subscribe to State Changes with use_store Source: https://intendednull.github.io/yewdux/print.html The use_store hook subscribes components to store updates, triggering re-renders automatically. Must be called at the top level of a function component. ```rust #![allow(unused)] fn main() { extern crate yewdux; extern crate yew; use yewdux::prelude::*; use yew::prelude::*; #[derive(PartialEq, Default, Store)] struct State { count: u32, } #[function_component] fn ViewCount() -> Html { let (state, dispatch) = use_store::(); html!(state.count) } } ``` -------------------------------- ### Using use_store Hook in Yew Component Source: https://intendednull.github.io/yewdux/dispatch.html Access the store's state and dispatch function within a Yew functional component using the `use_store` hook. Ensure hooks are used at the top level of the component. ```rust extern crate yewdux; extern crate yew; use yewdux::prelude::*; use yew::prelude::*; #[derive(Default, PartialEq, Store)] struct State { count: u32, } #[function_component] fn MyComponent() -> Html { let (state, dispatch) = use_store::(); html! { // Component stuff here } } ``` -------------------------------- ### Use Derived State in Components Source: https://intendednull.github.io/yewdux/derived_state.html Access derived state in components using `use_store_value` just like any other store. Components automatically re-render when the derived state they depend on changes. ```rust #![allow(unused)] fn main() { #[function_component] fn App() -> Html { let (count, dispatch) = use_store::(); let is_even = use_store_value::(); let multiplied = use_store_value::(); let onclick = dispatch.reduce_mut_callback(|state| state.count += 1); html! { <>

{"Count: "}{ count.count }

{"Is Even: "}{ is_even.status.to_string() }

{"Multiplied by 10: "}{ multiplied.value }

} } } ``` -------------------------------- ### Access Dispatch in Functional Components Source: https://intendednull.github.io/yewdux/print.html Use the use_store hook within Yew functional components to obtain a dispatch instance. ```rust #![allow(unused)] fn main() { extern crate yewdux; extern crate yew; use yewdux::prelude::*; use yew::prelude::*; #[derive(Default, PartialEq, Store)] struct State { count: u32, } #[function_component] fn MyComponent() -> Html { let (state, dispatch) = use_store::(); html! { // Component stuff here } } } ``` -------------------------------- ### Mutate State with Reducer Variants Source: https://intendednull.github.io/yewdux/print.html Uses _mut variants for less boilerplate. Requires the Store to implement Clone. ```rust #![allow(unused)] fn main() { extern crate yewdux; extern crate yew; use yewdux::prelude::*; use yew::prelude::*; #[derive(Default, PartialEq, Clone, Store)] struct State { count: u32, } // Create a global dispatch let dispatch = Dispatch::::global(); // Mutate the current value dispatch.reduce_mut(|state| state.count += 1); // Create a callback to mutate the value when a button is clicked let onclick = dispatch.reduce_mut_callback(|counter| counter.count += 1); html! { }; } ``` -------------------------------- ### Using Rc::make_mut for Copy-on-Write State Mutation Source: https://intendednull.github.io/yewdux/dispatch.html Leverage `Rc::make_mut` within a `Reducer` implementation for Copy-on-Write (CoW) behavior, allowing in-place mutation of the state when necessary. ```rust extern crate yewdux; use std::rc::Rc; use yewdux::prelude::*; #[derive(Default, PartialEq, Clone, Store)] struct State { count: u32, } enum Msg { AddOne, } impl Reducer for Msg { fn apply(self, mut state: Rc) -> Rc { let state_mut = Rc::make_mut(&mut state); match self { Msg::AddOne => state_mut.count += 1, }; state } } ``` -------------------------------- ### Define a Yewdux Listener Source: https://intendednull.github.io/yewdux/listeners.html Implement the Listener trait to define a store to watch and the logic to execute upon state changes. ```rust #![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) { yewdux::log::info!("state changed: {:?}", state); } } } ``` -------------------------------- ### Modify State with Dispatch Source: https://intendednull.github.io/yewdux/print.html Perform state updates using set, reduce, and reduce_callback methods on a Dispatch instance. ```rust #![allow(unused)] fn main() { extern crate yewdux; extern crate yew; use yewdux::prelude::*; use yew::prelude::*; #[derive(Default, PartialEq, Store)] struct State { count: u32, } // Create a global dispatch let dispatch = Dispatch::::global(); // Set the value immediately dispatch.set(State { count: 0 }); // Set the value immediately based on the last value dispatch.reduce(|state| State { count: state.count + 1}.into()); // Create a callback to set the value when a button is clicked let onclick = dispatch.reduce_callback(|state| State { count: state.count + 1}.into()); html! { }; } ``` -------------------------------- ### Consume Derived State in Components Source: https://intendednull.github.io/yewdux/print.html Access derived state in Yew components using the same hooks as standard stores. ```rust #![allow(unused)] fn main() { #[function_component] fn App() -> Html { let (count, dispatch) = use_store::(); let is_even = use_store_value::(); let multiplied = use_store_value::(); let onclick = dispatch.reduce_mut_callback(|state| state.count += 1); html! { <>

{"Count: "}{ count.count }

{"Is Even: "}{ is_even.status.to_string() }

{"Multiplied by 10: "}{ multiplied.value }

} } } ``` -------------------------------- ### Functional Component with use_store Hook Source: https://intendednull.github.io/yewdux/print.html Use the `use_store` hook in functional components to access and modify global state. Ensure `YewduxRoot` is an ancestor of components using this hook. ```rust #![allow(unused)] fn main() { extern crate yew; extern crate yewdux; use yew::prelude::*; use yewdux::prelude::*; #[derive(Default, Clone, PartialEq, Eq, Store)] struct State { count: u32, } #[function_component] fn Counter() -> Html { let (state, dispatch) = use_store::(); let onclick = dispatch.reduce_mut_callback(|state| state.count += 1); html! { <>

{ state.count }

} } #[function_component] fn App() -> Html { // YewduxRoot must be kept above all components that use any of your stores. html! { } } } ``` -------------------------------- ### Optimizing Re-renders with use_selector Source: https://intendednull.github.io/yewdux/print.html Use the use_selector hook to subscribe to specific parts of the state, ensuring the component only re-renders when that specific data changes. ```rust #![allow(unused)] fn main() { extern crate yewdux; extern crate yew; use yewdux::prelude::*; use yew::prelude::*; #[derive(Default, Clone, PartialEq, Store)] struct User { first_name: String, last_name: String, } #[function_component] fn DisplayFirst() -> Html { // This will only re-render when the first name has changed. It will **not** re-render if any // other field has changed. // // Note: we are cloning a string. Probably insignificant for this example, however // sometimes it may be beneficial to wrap fields that are expensive to clone in an `Rc`. let first_name = use_selector(|state: &User| state.first_name.clone()); html! {

{ first_name }

} } } ``` -------------------------------- ### Manually Implement Derived State Source: https://intendednull.github.io/yewdux/print.html Register derived state relationships manually within the new method of a custom Store implementation. ```rust #![allow(unused)] fn main() { #[derive(Default, Clone, PartialEq)] struct CountIsEven { status: bool, } impl DerivedFromMut for CountIsEven { fn on_change(&mut self, state: Rc) { 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::(); // Initialize with current Count value let status = cx.get::().count % 2 == 0; Self { status } } fn should_notify(&self, old: &Self) -> bool { self != old } } } ``` -------------------------------- ### Access the Global Yewdux Context Source: https://intendednull.github.io/yewdux/print.html Use the global context for thread-local state access, which is supported on wasm targets. ```rust #![allow(unused)] fn main() { extern crate yewdux; use yewdux::prelude::*; #[derive(Clone, PartialEq, Default, Store)] struct Counter(u32); // These are equivalent! let dispatch_1 = Dispatch::::global(); let dispatch_2 = Dispatch::::new(&yewdux::Context::global()); dispatch_1.set(Counter(1)); assert!(dispatch_1.get() == dispatch_2.get()); } ``` -------------------------------- ### Retrieve Current State without Subscription Source: https://intendednull.github.io/yewdux/print.html Uses Dispatch::get to read state immediately. Note that this does not trigger component re-renders on state changes. ```rust #![allow(unused)] fn main() { extern crate yewdux; use std::rc::Rc; use yewdux::prelude::*; #[derive(PartialEq, Default, Store)] struct State { count: u32, } // Create a dispatch from the global context. This works for non-global contexts too, we would just // pass in the context we want. let dispatch = Dispatch::::global(); let state: Rc = dispatch.get(); } ``` -------------------------------- ### Apply Predictable Mutations with Messages Source: https://intendednull.github.io/yewdux/print.html Defines messages and implements the Reducer trait to apply state changes. ```rust #![allow(unused)] fn main() { extern crate yewdux; extern crate yew; use std::rc::Rc; use yew::prelude::*; use yewdux::prelude::*; #[derive(Default, PartialEq, Clone, Store)] struct State { count: u32, } enum Msg { AddOne, } impl Reducer for Msg { fn apply(self, state: Rc) -> Rc { match self { Msg::AddOne => State { count: state.count + 1 }.into(), } } } let dispatch = Dispatch::::global(); dispatch.apply(Msg::AddOne); let onclick = dispatch.apply_callback(|_| Msg::AddOne); html! { }; } ```