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
Inspired by React's `useEffect` and Vue's `watchEffect`, `resonant` is a compact utility library that mitigates the inherent burdens of managing observable data, including dependency tracking; caching and cache invalidation; and object dereferencing and finalization.
44
+
Inspired by React's `useEffect` and Vue's `watchEffect`, `resonant` is a compact utility library that mitigates the overhead of managing observable data, such as dependency tracking; caching and cache invalidation; and object dereferencing and finalization.
45
+
46
+
In `resonant`, an effect is a computation that is automatically invoked any time its reactive state changes. An effect's reactive state is any state that is accessed inside the effect body (specifically, the function passed to the `effect` initializer). A deterministic heuristic follows that any data access that triggers getters will be visible to and therefore tracked by the effect.
43
47
44
-
In `resonant`, an effect is a computation that is automatically invoked any time its reactive state changes.
48
+
This reactive state 'resonates', hence `resonant`.
49
+
50
+
### <aname="docs_effect"></a> Creating an Effect
45
51
46
52
To create an effect, you must first make the target object (the effect state) reactive with the `resonant` function:
47
53
@@ -56,7 +62,7 @@ const plainObject = {
56
62
const r =resonant(plainObject);
57
63
```
58
64
59
-
Now, `r` is equipped with deep reactivity. All get / set operations will trigger any effects that happen to be observing the data.
65
+
`r` is now equipped with deep reactivity. All getters / setters will trigger any effects that happen to be observing the data.
60
66
61
67
Let's create an effect:
62
68
@@ -77,9 +83,9 @@ effect(() => {
77
83
});
78
84
```
79
85
80
-
The effect will be invoked immediately. Next, the effect is cached and tracks `r` as a reactive dependency. Any time `r.x` or `r.y`change, the effect will run.
86
+
The effect will be invoked immediately. Next, the effect is cached and tracks `r` as a reactive dependency. Any time `r.x` or `r.y`is mutated, the effect will run.
81
87
82
-
This works with branching and nested conditionals; if the effect encounters new properties by way of conditional logic, it tracks them as dependencies.
88
+
This paradigm works with branching and nested conditionals; if the effect encounters new properties by way of conditional logic, it tracks them as dependencies.
83
89
84
90
```ts
85
91
const r =resonant({
@@ -106,20 +112,120 @@ r.x.y.k = 1;
106
112
// the effect will see the second condition and begin tracking `r.x.y.z`
107
113
```
108
114
109
-
`resonant` uses weak references; deleted properties to which there are no references will be finalized so they may be garbage collected, as will all of that property's dependencies and effects. Finally, to nullify a resonant object's reactivity, use the `revokes` store:
115
+
Effect dependencies are tracked lazily; the effect only ever cares about resonant data that it can see.
116
+
117
+
`resonant` uses weak references; deleted properties to which there are no references will be finalized so they may be garbage collected, as will all of that property's dependencies and effects.
118
+
119
+
### <aname="docs_control"></a> Starting and Stopping an Effect
120
+
121
+
To control an effect, each effect initializer returns unique `stop`, `start`, and `toggle` handlers. These functions are used to pause, resume, or toggle the effect's active state.
122
+
123
+
Use `stop` to pause an effect. The effect will not run during this period. Stopping an effect flushes its dependency cache, so subsequent `start` or `toggle` calls are akin to creating the effect anew.
Use `start` to transition the effect to an active state. `start` is idempotent; if the effect is already active, invoking `start` will *not* immediately trigger the effect. Otherwise, `start` - like instantiating a new effect - will run the effect immediately.
149
+
150
+
```ts
151
+
import { resonant, effect } from'resonant';
152
+
153
+
const r =resonant({ x: 1 });
154
+
let c =0;
155
+
156
+
const { stop, start } =effect(() => {
157
+
c+=r.x;
158
+
});
159
+
// initial run - r.x == 1, c == 1
160
+
161
+
r.x++;
162
+
// r.x == 2, c == 3
163
+
164
+
stop();
165
+
166
+
r.x++;
167
+
// r.x == 3, c == 3
168
+
169
+
start();
170
+
// initial run - r.x == 3, c == 6
171
+
172
+
r.x++;
173
+
// r.x == 4, c == 7
174
+
```
175
+
176
+
Use `toggle` to toggle the effect's active state. Toggle invokes the appropriate `start` or `stop` handler and returns a boolean indicating whether the effect's state is active.
177
+
178
+
```ts
179
+
import { resonant, effect } from'resonant';
180
+
181
+
const r =resonant({ x: 1 });
182
+
let c =0;
183
+
let isActive =true;
184
+
185
+
const { toggle } =effect(() => {
186
+
c+=r.x;
118
187
});
188
+
// initial run - r.x == 1, c == 1
189
+
190
+
r.x++;
191
+
// r.x == 2, c == 3
192
+
193
+
isActive=toggle();
194
+
// isActive == false
195
+
196
+
r.x++;
197
+
// r.x == 3, c == 3
198
+
199
+
isActive=toggle();
200
+
// isActive == true
201
+
// initial run - r.x == 3, c == 6
202
+
203
+
r.x++;
204
+
// r.x == 4, c == 7
205
+
```
206
+
207
+
### <aname="docs_defer"></a> Deferred Effects
208
+
209
+
Effects may be initialized lazily with the `lazy` option. Passing this optional flag to the `effect` initializer will initialize the effect in an inactive state. The effect will *not* run immediately; either the effect's `start` or `toggle` handler *must be invoked before the effect can trigger*.
210
+
211
+
```ts
212
+
import { resonant, effect } from'resonant';
213
+
214
+
const r =resonant({ x: 1 });
215
+
let c =0;
216
+
217
+
const { start } =effect(() => {
218
+
c+=r.x;
219
+
}, { lazy: true });
220
+
// no initial run - r.x == 1, c == 0
221
+
222
+
r.x++;
223
+
// r.x == 2, c == 0
119
224
120
-
const revoke =revokes.get(r);
225
+
start();
121
226
122
-
revoke();
227
+
r.x++;
228
+
// r.x == 3, c == 3
123
229
```
124
230
125
-
Full documentation can be found [here](https://matthewzito.github.io/resonant/resonant.html)
231
+
Full documentation and type signatures can be found [here](https://matthewzito.github.io/resonant/resonant.html)
0 commit comments