Crates.io | yewv |
lib.rs | yewv |
version | 0.2.3 |
source | src |
created_at | 2022-03-29 13:38:56.275572 |
updated_at | 2022-04-14 19:49:04.938925 |
description | A lightning fast state management module for Yew |
homepage | https://github.com/yewv/yewv/tree/v0.2 |
repository | https://github.com/yewv/yewv/tree/v0.2 |
max_upload_size | |
id | 558545 |
size | 42,487 |
A lightning fast state management module for Yew built with performance and simplicity as a first priority.
If you wish to use a store alongside Yew fonction components, this library is made for you.
Add the following dependency to your Cargo.toml
.
[dependencies]
yewv = "0.2"
The following need to be respected while using this library:
ContextProvider
.use_store
/use_service
.map_ref
& watch_ref
, map
& watch
are hooks and are therefore constrained to certain rules:
// main.rs
use yew::prelude::*;
use yewv::*;
struct AppState {
count: i32,
}
#[function_component(App)]
fn app() -> Html {
let store = StoreContext::new(AppState { count: 0 });
html! {
<ContextProvider<StoreContext<AppState>> context={store}>
<Counter />
<Counter />
</ContextProvider<StoreContext<AppState>>>
}
}
#[function_component(Counter)]
fn counter() -> Html {
let store = use_store::<AppState>();
let count = store.map_ref(|state| &state.count);
let onclick = {
let store = store.clone();
move |_| {
let state = store.state();
store.set_state(AppState {
count: state.count + 1,
});
}
};
html! {
<button {onclick}>{format!("{} +", count)}</button>
}
}
fn main() {
yew::start_app::<App>();
}
// main.rs
use yew::prelude::*;
use yewv::*;
struct AppState {
count: i32,
}
struct AppService {
store: StoreContext<AppState>,
}
impl AppService {
fn increment_count(&self) {
let state = self.store.state();
self.store.set_state(AppState {
count: state.count + 1,
});
}
}
#[function_component(App)]
fn app() -> Html {
let store = StoreContext::new(AppState { count: 0 });
let service = ServiceContext::new(AppService {
store: store.clone(),
});
html! {
<ContextProvider<StoreContext<AppState>> context={store}>
<ContextProvider<ServiceContext<AppService>> context={service}>
<Counter />
<Counter />
</ContextProvider<ServiceContext<AppService>>>
</ContextProvider<StoreContext<AppState>>>
}
}
#[function_component(Counter)]
fn counter() -> Html {
let service = use_service::<AppService>();
let store = use_store::<AppState>();
let count = store.map_ref(|state| &state.count);
let onclick = move |_| service.increment_count();
html! {
<button {onclick}>{format!("{} +", count)}</button>
}
}
fn main() {
yew::start_app::<App>();
}
If you only wish to reference a value owned by the store, you should use map_ref
.
As opposed to map
, map_ref
doesn't take ownership of the referenced value.
It is usually preferable to use map_ref
over map
when possible.
However, it is not always possible to use map_ref
. For instance, if the value you wish to access is not owned by the store state, you will need to use map
:
let length = store.map(|state| state.some_vector.len());
The store utilizes highly optimized custom hooks for better performance and memory efficiency.
Subscriptions done to the store with map
, map_ref
, watch
and watch_ref
will only trigger a render on the component if the observed value has changed.
Instead of propagating clone/copy of the application state throughout components, references are used.
When you are observing a value in a store, make sure you are not taking more than necessary. For instance, if you are only interested in a single value from a vector, there is no need to reference the entire vector:
let first = store.map_ref(|state| &state.some_vector[0]);
let last = store.map_ref(|state| state.some_vector.iter().last().expect("to have a value"));
When and where it makes sense, try to break your monolithic stores into multiple. Doing so will improve the performance of the application as a whole.