1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//! 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`.
//! ```toml
//! [dependencies]
//! yewv = "0.2"
//! ```
//! # Usage
//! The following need to be respected while using this library:
//! 1. Only works with Yew function components.
//! 2. Store and service contexts must be registered in a **parent** or **root** component with `ContextProvider`.
//! 3. Store and service need to be used in a **child** component with `use_store`/`use_service`.
//! 4. 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
//! ```rust
//! 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>
//! }
//! }
//! ```
//!
//! ## Simple app with store and service
//! ```rust
//! 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>
//! }
//! }
//! ```
//!
//! ## 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`:
//! ```rust
//! use yew::prelude::*;
//! use yewv::*;
//!
//! struct StoreState {
//! vector: Vec<i32>
//! }
//!
//! #[function_component(Test)]
//! fn test() -> Html {
//! let store = use_store::<StoreState>();
//! let length = store.map(|state| state.vector.len());
//!
//! html!{ { length } }
//! }
//! ```
//!
//! # 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:
//! ```rust
//! use yew::prelude::*;
//! use yewv::*;
//!
//! struct StoreState {
//! vector: Vec<i32>
//! }
//!
//! #[function_component(Test)]
//! fn test() -> Html {
//! let store = use_store::<StoreState>();
//! let first = store.map_ref(|state| &state.vector[0]);
//! let last = store.map_ref(|state| state.vector.iter().last().expect("to have a value"));
//!
//! html!{ format!("{} and {}", first, last) }
//! }
//! ```
//!
//! ## 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](https://github.com/rust-lang/rust) - [MIT](https://github.com/rust-lang/rust/blob/master/LICENSE-MIT) or [Apache-2.0](https://github.com/rust-lang/rust/blob/master/LICENSE-APACHE)
//! - [Yew](https://github.com/yewstack/yew) - [MIT](https://github.com/yewstack/yew/blob/master/LICENSE-MIT) or [Apache-2.0](https://github.com/yewstack/yew/blob/master/LICENSE-APACHE)
pub use *;