You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Easy State consists of two functions: `easyComp` and `easyStore`.
29
+
Easy State consists of two functions:
30
+
31
+
-`easyComp` makes React's own component level state management simpler.
32
+
-`easyStore` creates global state stores for complex apps.
18
33
19
34
### easyComp
20
35
21
-
Wrapping your components with the `easyComp` function simplifies React's own state management in the following ways.
36
+
Wrapping your components with the `easyComp` function provides the following benefits.
22
37
23
38
- It allows you to mutate the component's state directly, without calling `setState`.
24
39
25
-
- It binds your component's methods to the component, to allow them to be passed as callbacks.
40
+
- It binds your component's methods to the component.
26
41
27
42
```js
28
43
importReact, { Component } from'react'
@@ -57,102 +72,84 @@ class Hello extends Component {
57
72
exportdefaulteasyComp(Hello)
58
73
```
59
74
60
-
Apart from the simplified syntax wrapping your component's with `EasyComp` provides the following benefits.
75
+
*Make sure to wrap all of your components - including stateful and stateless ones - before you export them.*
61
76
62
-
- The state is just an object, which updates synchronously when you update it. You don't have to worry about the asynchronous nature of `setState`.
77
+
In addition to the boilerplate reduction, `easyComp` comes with a bunch of additional benefits that may not be obvious at first glance.
63
78
64
-
-State mutations are picked up and they trigger the render method when appropriate.
79
+
-The state becomes a simple object, which updates synchronously. You don't have to worry about immutable state updates or the asynchronous nature of `setState`. If you are not sure about the meaning of this check out [this article](https://medium.freecodecamp.org/functional-setstate-is-the-future-of-react-374f30401b6b) about `setState`.
65
80
66
-
- The render method is only triggered if it is affected by state mutations. If it doesn't use the mutated part of the state or the mutation doesn't change the state, the render method is not triggered.
81
+
- The render method is only triggered if it is affected by the state mutations. If it doesn't use the mutated part of the state or the mutation doesn't change the state, the render method is not triggered.
67
82
68
83
- The render method is never executed immediately. Triggered renders are collected and executed asynchronously in one batch.
69
84
70
-
- Duplicates renders are removed. A render never runs twice in one batch - no matter how many times it got triggered. Renders run in first trigger order.
85
+
- Renders always run before the next repaint.
86
+
87
+
- Duplicates renders are removed. A render never runs twice in one batch - no matter how many times it got triggered.
71
88
72
89
- Renders may trigger others renders by mutating the state. In this case loops are automatically resolved.
73
90
74
-
- Renders always run before the next repaint.
75
-
76
-
- Easy State implements an optimal `shouldComponentUpdate` for your components, so you don't have to worry about doing it by hand.
91
+
- Easy State implements an optimal `shouldComponentUpdate` for your components.
77
92
78
-
As a result the state is always fresh and a stable and fresh view is always achieved before the next repaint with the minimal number of required renders.
93
+
As a result the state is always fresh and a stable and a fresh view is always achieved before the next repaint with the minimal number of required renders.
79
94
80
95
### easyStore
81
96
82
-
`EasyStore` creates global state stores, to handle data that do not fit into component state. Wrapping an object with `easyStore` has to following effects.
97
+
`easyStore` creates global state stores, to handle data that do not fit into component state. Wrapping an object with `easyStore` has to following effects.
83
98
84
99
- It transforms the object into a reactive data store, which triggers appropriate renders on mutations.
85
100
86
-
- It binds your object's methods to the object, to allow them to be passed as callbacks.
`easyStore` creates global state stores. A store is just an object and it behaves much like the component state from `easyComp`. It can be handled like a normal JavaScript object and it automatically triggers the appropriate render methods when it is mutated.
119
-
120
-
## State management tutorial
121
-
122
-
Easy State promotes a healthy balance between local and global state. The following use cases will give a rough guide when to use which.
123
-
124
-
### Widgets and libraries
125
-
126
-
This is an easy decision. Always use local component state for reusable components. They should be robust and versatile without implicit dependencies. Check out the introductory [clock example]() for some code.
132
+
*Make sure to wrap your component with `easyComp` even if it uses global stores only and no local state.*
127
133
128
-
### Application state
129
-
130
-
Most application state is usually persistent and singleton. It should be managed in global stores.
134
+
- Global stores are simple objects and there is no limitation on what you can do with them. As an example feel free to use expando properties, arrays, deeply nested objects, ES6 collections or getters/setters in your stores.
131
135
132
-
-A good example is the currently logged in user. There is only one user at a time and user data should be easily available anywhere anytime. Perfect candidate for singleton global state.
136
+
-Render methods are only triggered if they are affected by the store mutations. If they don't use the mutated part of the store or the mutation doesn't change the store, the render method is not triggered.
133
137
134
-
-Another nice example is user inputs, which should go into the URL or change the browser history. These are inherently global because they affect global concepts (URL and browser history). Some example for these are filters, date ranges and sorting primitives.
138
+
-Render methods are never executed immediately. Triggered renders are collected and executed asynchronously in one batch.
135
139
140
+
- Renders always run before the next repaint.
136
141
137
-
### Application pages
142
+
- Duplicates renders are removed. A render never runs twice in one batch - no matter how many times it got triggered.
138
143
139
-
A typical app has several independent pages. There is only one active page at a time, which makes them a nice candidate for singleton global state stores. However pages are not as persistent as the app user for example, which makes them lean towards local state management.
144
+
- Renders may trigger others renders by mutating the store again. In this case loops are automatically resolved.
140
145
141
-
Page state usually has filters and inputs, which goes into the URL and browser history. In this case it is inherently global and it should be handled in a global state store. These stores persist between page transitions, but this is perfectly fine. As a bonus you get a faster transition, because you don't always have to re-fetch all of the data. If you do not want data to linger around clean up the relevant parts in `componentWillUnmount`.
146
+
As a result the stores are always fresh and a stable and a fresh view is always achieved before the next repaint with the minimal number of required renders.
You can compare Easy State with plain React and other state management libraries with the below benchmarks. Easy State performs a bit better than MobX, a bit worse than plain optimized React and similarly to Redux.
@@ -165,14 +162,48 @@ The list of benchmarks will expand in the future.
165
162
- React native is not yet supported
166
163
- IE is not supported
167
164
165
+
## Performance
166
+
167
+
You can compare Easy State with plain React and other state management libraries with the below benchmarks. Easy State performs a bit better than MobX, a bit worse than plain optimized React and similarly to Redux.
Finding the right balance between local component state and global state stores is not always a trivial task. This section gives you some general guide lines when to use which.
176
+
177
+
### Reusable widgets
178
+
179
+
This is an easy decision. Always use local component state for reusable components. Depending on global stores would interfere with their reusability and break them. Check out the introductory [clock example](/examples/clock/) for some code.
180
+
181
+
### Application state
182
+
183
+
Application state should usually be managed in global stores. It is singleton and its is usually persistent while the app is open. You can find a few candidates for global storage below.
184
+
185
+
- The currently logged in user is a good example. There is only one user at a time and user data should be easily available anywhere anytime. It is a perfect candidate for a singleton global store.
186
+
187
+
- User inputs, which should go into the URL or change the browser history are also great examples. These are inherently global because they affect global concepts - like the URL and browser history. Some example for these are filters, date ranges and sorting primitives.
188
+
189
+
Not everything fits in global stores though. You can find a few cases below when using the local component state makes more sense then global stores.
190
+
191
+
- Utility and meta data should go into component state. For example you may have a component which handles recent history for an input field. It may make sense to receive the data for the input from a global store and manage the history meta data in the local state. Check out the [contacts table example](/examples/contacts/) for some code.
192
+
193
+
### Application pages
194
+
195
+
Application pages deserve a special mention. A typical app has several pages but, only one of them is active at a time. This makes them a nice candidate for singleton global state stores. However pages are not as persistent as the app's user for example, which makes them lean towards local state management.
196
+
197
+
Page state usually has properties, which belong in the URL and browser history. In this case it is inherently global and it should be handled in a global store. These stores persist between page transitions, but this is perfectly fine. As a bonus you get a faster transition, because you don't always have to re-fetch all of the data. If you do not want data to linger around clean up the relevant parts in `componentWillUnmount`.
198
+
168
199
## How does it work?
169
200
170
-
Under the hood it uses the [@nx-js/observer-util](https://github.com/nx-js/observer-util) library, which relies on ES6 Proxies to observe state changes. Thanks to the Proxies it doesn't have edge cases or limitations. You can write any JS code without worrying about the render function. [This blog post](https://blog.risingstack.com/writing-a-javascript-framework-data-binding-es6-proxy/) gives a little sneak peek under the hood of the `observer-util`.
201
+
Under the hood Easy State uses the [@nx-js/observer-util](https://github.com/nx-js/observer-util) library, which relies on ES6 Proxies to observe state changes. Thanks to the Proxies it doesn't have edge cases or limitations. You can write any JS code without worrying about the render function. [This blog post](https://blog.risingstack.com/writing-a-javascript-framework-data-binding-es6-proxy/) gives a little sneak peek under the hood of the `observer-util`.
171
202
172
203
## Contributing
173
204
174
-
Contributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains at 100%. Thx!
205
+
Contributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!
175
206
176
207
## The NX Framework
177
208
178
-
This library is a side effect of the front-end framework I have been working on in the past year. Please take a look at the [NX Framework](https://nx-framework.com/) if you have some time. Have a nice day!
209
+
This library is a side project of the front-end framework I have been working on in the past year. Please take a look at the [NX Framework](https://nx-framework.com/) if you have some time. Thanks and have a nice day!
A super simple digital clock widget. It uses component state only and no global store, which is the general rule for **reusable** components and widgets.
An editable contact list, which demonstrates how to balance between local component state and global stores. It manages the central data and logic in a global store and keeps temporary utility data in component states. Dependency injection is handled by plain imports and react props.
This is a lighter version of the well-known React [TodoMVC](http://todomvc.com/). It handles all of the state in a separate global store and relies heavily on JS getters and setter to provide a clear and simple state management. Be sure to click all the buttons in the demo that you can find.
0 commit comments