@@ -8,6 +8,61 @@ Rules of thumb:
88
99Other libraries or frameworks often call state providers "Stores".
1010
11+ ## How Reactivity Works: The Effects-Based System
12+
13+ Neo.mjs State Providers implement a powerful effects-based reactivity system,
14+ which automatically tracks dependencies and re-evaluates computations when
15+ their underlying data changes. This system is built around two core concepts:
16+
17+ ### 1. The ` Neo.core.Effect ` Class
18+
19+ At the heart of the reactivity is the ` Neo.core.Effect ` class. An ` Effect `
20+ is a mechanism that encapsulates a function (its "effect function") and
21+ automatically re-runs this function whenever any of the reactive data
22+ properties it accesses change.
23+
24+ * ** Implicit Dependency Tracking:** When your effect function (e.g., a formula
25+ or a binding formatter) reads a reactive data property (e.g., ` data.user.firstName ` ),
26+ the ` Effect ` automatically "subscribes" to changes in that property.
27+ * ** Automatic Re-evaluation:** If ` data.user.firstName ` changes, the ` Effect `
28+ detects this and automatically re-executes its effect function, ensuring
29+ that any dependent computations or UI updates are performed.
30+
31+ ### 2. The Hierarchical Data Proxy
32+
33+ When you access data within a State Provider (e.g., in a ` bind ` configuration
34+ or a ` formula ` ), you are interacting with a special ` Proxy ` object. This proxy
35+ is created by ` Neo.state.createHierarchicalDataProxy ` and provides a unified
36+ view of data across the entire State Provider hierarchy (current provider and
37+ all its parents).
38+
39+ * ** Seamless Data Access:** You can access any data property, whether it lives
40+ in the current State Provider or a parent, using simple dot notation (e.g.,
41+ ` data.myProperty ` or ` data.user.address.street ` ).
42+ * ** Enabling Dependency Tracking:** This proxy works in conjunction with
43+ ` Neo.core.Effect ` to enable implicit dependency tracking. When an ` Effect `
44+ reads a property through this proxy, the proxy notifies the ` Effect ` about
45+ the access, allowing the ` Effect ` to register that property as a dependency.
46+
47+ ### How Bindings and Formulas Utilize Effects
48+
49+ * ** Bindings (` bind ` config):** When you define a ` bind ` configuration for a
50+ component (e.g., ` bind: {text: data => data.hello} ` ), Neo.mjs creates an
51+ ` Effect ` . The effect function is your formatter (` data => data.hello ` ).
52+ Whenever ` data.hello ` changes, the ` Effect ` re-runs, re-evaluates the
53+ formatter, and updates the component's ` text ` config.
54+
55+ * ** Formulas (` formulas ` config):** Similarly, for ` formulas ` defined in a
56+ State Provider, each formula function is wrapped in an ` Effect ` . When the
57+ formula accesses data (e.g., ` data.a + data.b ` ), the ` Effect ` tracks ` data.a `
58+ and ` data.b ` as dependencies. If either changes, the ` Effect ` re-runs the
59+ formula, and its computed result is automatically updated in the State Provider's
60+ data.
61+
62+ This effects-based system significantly reduces boilerplate, making state
63+ management intuitive and efficient by handling dependency tracking and updates
64+ automatically.
65+
1166## Inline State Providers
1267### Direct Bindings
1368``` javascript live-preview
@@ -111,9 +166,9 @@ Inside the Container are 3 Labels which bind their `text` config to a combinatio
111166
112167We are showcasing 3 different ways how you can define your binding (resulting in the same output).
113168
114- In case any of the bound data props changes, all bound Configs will check for an update.
169+ In case any of the bound data props changes, the underlying ` Effect ` for that binding will re-evaluate, and all bound Configs will update.
115170
116- Important: The Config setter will only trigger in case there is a real change for the bound output.
171+ Important: The Config setter will only trigger in case there is a real change for the bound output, ensuring efficient updates .
117172
118173We also added 2 Buttons to change the value of each data prop, so that we can see that the bound Label texts
119174update right away.
@@ -252,7 +307,7 @@ which contains the nested props `firstname` and `lastname`.
252307We can bind to these nested props like before:</br >
253308` bind: {text: data => data.user.firstname + ' ' + data.user.lastname} `
254309
255- Any change of a nested data prop will directly get reflected into the bound components.
310+ Any change of a nested data prop will directly trigger the associated ` Effect ` and get reflected into the bound components.
256311
257312We can update a nested data prop with passing its path:</br >
258313` data => data.component.setState({'user.lastname': 'Rahder'}) `
@@ -498,15 +553,10 @@ class MainViewStateProvider extends StateProvider {
498553 static config = {
499554 className: ' Guides.vm7.MainViewStateProvider' ,
500555
501- data: {
502- myStoreCount: 0
503- },
504-
505556 stores: {
506557 // Define a store using a class reference
507558 mySharedStore: {
508- module : MyDataStore,
509- listeners: {countChange: ' onMyStoreCountChange' }
559+ module : MyDataStore
510560 },
511561 // Define another store using an inline configuration
512562 anotherStore: {
@@ -522,11 +572,9 @@ class MainViewStateProvider extends StateProvider {
522572 {value: 30 }
523573 ]
524574 }
525- }
526- }
575+ },
527576
528- onMyStoreCountChange (data ) {
529- this .data .myStoreCount = data .value // Reactive
577+
530578 }
531579}
532580MainViewStateProvider = Neo .setupClass (MainViewStateProvider);
@@ -557,7 +605,7 @@ class MainView extends Container {
557605 module: Label,
558606 style : {margin: ' auto' },
559607 bind: {
560- text : data => ` Count: ${ data .myStoreCount } `
608+ text : data => ` Count: ${ data .stores . mySharedStore . count } `
561609 }
562610 }, {
563611 module: Button,
0 commit comments