SSR Support
By default Yewdux uses a global Context
that is shared thread-locally. This means we can share
state from anywhere in our code as long as it's within the same thread. Wasm applications are
strictly single threaded (without workers), so it isn't a problem.
However the same cannot be said for server side rendering. It is very possible the server is executing in a multi-threaded environment, which could cause various problems for Yewdux's single-threaded assumption.
While multi-threaded globally shared state is technically possible, it is currently not supported.
Instead Yewdux offers a custom component to hold your shared application state: YewduxRoot
. This
ensures all state is kept inside your Yew app.
#![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::<State>(); let onclick = dispatch.reduce_mut_callback(|state| state.count += 1); html! { <> <p>{ state.count }</p> <button {onclick}>{"+1"}</button> </> } } #[function_component] fn App() -> Html { // YewduxRoot must be kept above all components that use any of your stores. html! { <YewduxRoot> <Counter /> </YewduxRoot> } } }
Yewdux hooks automatically detect when YewduxRoot is present, and use it accordingly.
SSR with struct components
For struct component support, refer to the higher order components pattern.
#![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<State>, } enum Msg { StateChanged(Rc<State>), } struct MyComponent { state: Rc<State>, dispatch: Dispatch<State>, } impl Component for MyComponent { type Properties = Props; type Message = Msg; fn create(ctx: &Context<Self>) -> 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<Self>, msg: Self::Message) -> bool { match msg { Msg::StateChanged(state) => { self.state = state; true } } } fn view(&self, ctx: &Context<Self>) -> Html { let count = self.state.count; let onclick = self.dispatch.reduce_mut_callback(|s| s.count += 1); html! { <> <h1>{ count }</h1> <button onclick={onclick}>{"+1"}</button> </> } } } #[function_component] fn MyComponentHoc() -> Html { let dispatch = use_dispatch::<State>(); html! { <MyComponent {dispatch} /> } } #[function_component] fn App() -> Html { // YewduxRoot must be kept above all components that use any of your stores. html! { <YewduxRoot> <MyComponentHoc /> </YewduxRoot> } } }