6 releases
0.2.3 | Apr 14, 2022 |
---|---|
0.2.2 | Apr 10, 2022 |
0.1.1 | Mar 30, 2022 |
#522 in GUI
32KB
366 lines
yewv
A lightning fast state management module for Yew built with performance and simplicity as a first priority.
Who is this for?
If you wish to use a store alongside Yew fonction components, this library is made for you.
Install
Add the following dependency to your Cargo.toml
.
[dependencies]
yewv = "0.2"
Usage
The following need to be respected while using this library:
- Only works with Yew function components.
- Store and service contexts must be registered in a parent or root component with
ContextProvider
. - Store and service need to be used in a child component with
use_store
/use_service
. - As opposed to
map_ref
&watch_ref
,map
&watch
are hooks and are therefore constrained to certain rules:- Should only be called inside Yew function components.
- Should not be called inside loops, conditions or callbacks.
Simple app with store
// 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>();
}
Simple app with store and service
// 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>();
}
map vs map_ref
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());
Why is it so fast?
Custom hooks
The store utilizes highly optimized custom hooks for better performance and memory efficiency.
Renders only when and where needed
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.
Reference VS Ownership
Instead of propagating clone/copy of the application state throughout components, references are used.
Good practices
Reference only what's needed
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"));
Segregation of stores in large applications
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.
Credits
- Rust - MIT or Apache-2.0
- Yew - MIT or Apache-2.0
Dependencies
~13MB
~235K SLoC