@ersbeth/picoflow 0.2.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/.cursor/plans/update-js-e795d61b.plan.md +567 -0
  2. package/.gitlab-ci.yml +24 -0
  3. package/.vscode/settings.json +3 -3
  4. package/CHANGELOG.md +51 -0
  5. package/IMPLEMENTATION_GUIDE.md +1578 -0
  6. package/README.md +62 -25
  7. package/biome.json +32 -32
  8. package/dist/picoflow.js +557 -1099
  9. package/dist/types/advanced/array.d.ts +0 -6
  10. package/dist/types/advanced/array.d.ts.map +1 -1
  11. package/dist/types/advanced/index.d.ts +5 -5
  12. package/dist/types/advanced/index.d.ts.map +1 -1
  13. package/dist/types/advanced/map.d.ts +114 -23
  14. package/dist/types/advanced/map.d.ts.map +1 -1
  15. package/dist/types/advanced/resource.d.ts +51 -12
  16. package/dist/types/advanced/resource.d.ts.map +1 -1
  17. package/dist/types/advanced/resourceAsync.d.ts +28 -13
  18. package/dist/types/advanced/resourceAsync.d.ts.map +1 -1
  19. package/dist/types/advanced/stream.d.ts +74 -16
  20. package/dist/types/advanced/stream.d.ts.map +1 -1
  21. package/dist/types/advanced/streamAsync.d.ts +69 -15
  22. package/dist/types/advanced/streamAsync.d.ts.map +1 -1
  23. package/dist/types/basic/constant.d.ts +44 -16
  24. package/dist/types/basic/constant.d.ts.map +1 -1
  25. package/dist/types/basic/derivation.d.ts +73 -24
  26. package/dist/types/basic/derivation.d.ts.map +1 -1
  27. package/dist/types/basic/disposable.d.ts +65 -6
  28. package/dist/types/basic/disposable.d.ts.map +1 -1
  29. package/dist/types/basic/effect.d.ts +27 -16
  30. package/dist/types/basic/effect.d.ts.map +1 -1
  31. package/dist/types/basic/index.d.ts +7 -8
  32. package/dist/types/basic/index.d.ts.map +1 -1
  33. package/dist/types/basic/observable.d.ts +62 -13
  34. package/dist/types/basic/observable.d.ts.map +1 -1
  35. package/dist/types/basic/signal.d.ts +35 -6
  36. package/dist/types/basic/signal.d.ts.map +1 -1
  37. package/dist/types/basic/state.d.ts +25 -4
  38. package/dist/types/basic/state.d.ts.map +1 -1
  39. package/dist/types/basic/trackingContext.d.ts +33 -0
  40. package/dist/types/basic/trackingContext.d.ts.map +1 -0
  41. package/dist/types/creators.d.ts +271 -26
  42. package/dist/types/creators.d.ts.map +1 -1
  43. package/dist/types/index.d.ts +60 -7
  44. package/dist/types/index.d.ts.map +1 -1
  45. package/dist/types/solid/converters.d.ts +5 -5
  46. package/dist/types/solid/converters.d.ts.map +1 -1
  47. package/dist/types/solid/index.d.ts +2 -2
  48. package/dist/types/solid/index.d.ts.map +1 -1
  49. package/dist/types/solid/primitives.d.ts +96 -4
  50. package/dist/types/solid/primitives.d.ts.map +1 -1
  51. package/docs/.vitepress/config.mts +110 -0
  52. package/docs/api/classes/FlowArray.md +489 -0
  53. package/docs/api/classes/FlowConstant.md +350 -0
  54. package/docs/api/classes/FlowDerivation.md +334 -0
  55. package/docs/api/classes/FlowEffect.md +100 -0
  56. package/docs/api/classes/FlowMap.md +512 -0
  57. package/docs/api/classes/FlowObservable.md +306 -0
  58. package/docs/api/classes/FlowResource.md +380 -0
  59. package/docs/api/classes/FlowResourceAsync.md +362 -0
  60. package/docs/api/classes/FlowSignal.md +160 -0
  61. package/docs/api/classes/FlowState.md +368 -0
  62. package/docs/api/classes/FlowStream.md +367 -0
  63. package/docs/api/classes/FlowStreamAsync.md +364 -0
  64. package/docs/api/classes/SolidDerivation.md +75 -0
  65. package/docs/api/classes/SolidResource.md +91 -0
  66. package/docs/api/classes/SolidState.md +71 -0
  67. package/docs/api/classes/TrackingContext.md +33 -0
  68. package/docs/api/functions/array.md +58 -0
  69. package/docs/api/functions/constant.md +45 -0
  70. package/docs/api/functions/derivation.md +53 -0
  71. package/docs/api/functions/effect.md +49 -0
  72. package/docs/api/functions/from.md +220 -0
  73. package/docs/api/functions/isDisposable.md +49 -0
  74. package/docs/api/functions/map.md +57 -0
  75. package/docs/api/functions/resource.md +52 -0
  76. package/docs/api/functions/resourceAsync.md +50 -0
  77. package/docs/api/functions/signal.md +36 -0
  78. package/docs/api/functions/state.md +47 -0
  79. package/docs/api/functions/stream.md +53 -0
  80. package/docs/api/functions/streamAsync.md +50 -0
  81. package/docs/api/index.md +118 -0
  82. package/docs/api/interfaces/FlowDisposable.md +65 -0
  83. package/docs/api/interfaces/SolidObservable.md +19 -0
  84. package/docs/api/type-aliases/FlowArrayAction.md +49 -0
  85. package/docs/api/type-aliases/FlowStreamDisposer.md +15 -0
  86. package/docs/api/type-aliases/FlowStreamSetter.md +27 -0
  87. package/docs/api/type-aliases/FlowStreamUpdater.md +32 -0
  88. package/docs/api/type-aliases/NotPromise.md +18 -0
  89. package/docs/api/type-aliases/SolidGetter.md +17 -0
  90. package/docs/api/typedoc-sidebar.json +1 -0
  91. package/docs/examples/examples.md +2313 -0
  92. package/docs/examples/patterns.md +649 -0
  93. package/docs/guide/advanced/disposal.md +426 -0
  94. package/docs/guide/advanced/solidjs.md +221 -0
  95. package/docs/guide/advanced/upgrading.md +464 -0
  96. package/docs/guide/introduction/concepts.md +56 -0
  97. package/docs/guide/introduction/conventions.md +61 -0
  98. package/docs/guide/introduction/getting-started.md +134 -0
  99. package/docs/guide/introduction/lifecycle.md +371 -0
  100. package/docs/guide/primitives/array.md +400 -0
  101. package/docs/guide/primitives/constant.md +380 -0
  102. package/docs/guide/primitives/derivations.md +348 -0
  103. package/docs/guide/primitives/effects.md +458 -0
  104. package/docs/guide/primitives/map.md +387 -0
  105. package/docs/guide/primitives/overview.md +175 -0
  106. package/docs/guide/primitives/resources.md +858 -0
  107. package/docs/guide/primitives/signal.md +259 -0
  108. package/docs/guide/primitives/state.md +368 -0
  109. package/docs/guide/primitives/streams.md +931 -0
  110. package/docs/index.md +47 -0
  111. package/docs/public/logo.svg +1 -0
  112. package/package.json +57 -41
  113. package/src/advanced/array.ts +208 -210
  114. package/src/advanced/index.ts +7 -7
  115. package/src/advanced/map.ts +178 -68
  116. package/src/advanced/resource.ts +87 -43
  117. package/src/advanced/resourceAsync.ts +62 -42
  118. package/src/advanced/stream.ts +113 -50
  119. package/src/advanced/streamAsync.ts +120 -61
  120. package/src/basic/constant.ts +82 -49
  121. package/src/basic/derivation.ts +128 -84
  122. package/src/basic/disposable.ts +74 -15
  123. package/src/basic/effect.ts +85 -77
  124. package/src/basic/index.ts +7 -8
  125. package/src/basic/observable.ts +94 -36
  126. package/src/basic/signal.ts +133 -105
  127. package/src/basic/state.ts +46 -25
  128. package/src/basic/trackingContext.ts +45 -0
  129. package/src/creators.ts +297 -54
  130. package/src/index.ts +96 -43
  131. package/src/solid/converters.ts +186 -67
  132. package/src/solid/index.ts +8 -2
  133. package/src/solid/primitives.ts +167 -65
  134. package/test/array.test.ts +592 -612
  135. package/test/constant.test.ts +31 -33
  136. package/test/derivation.test.ts +531 -536
  137. package/test/effect.test.ts +21 -21
  138. package/test/map.test.ts +233 -137
  139. package/test/resource.test.ts +119 -121
  140. package/test/resourceAsync.test.ts +98 -100
  141. package/test/signal.test.ts +51 -55
  142. package/test/state.test.ts +186 -168
  143. package/test/stream.test.ts +189 -189
  144. package/test/streamAsync.test.ts +186 -186
  145. package/tsconfig.json +19 -18
  146. package/typedoc.json +37 -0
  147. package/vite.config.ts +23 -20
  148. package/vitest.config.ts +7 -7
  149. package/api/doc/index.md +0 -31
  150. package/api/doc/picoflow.array.md +0 -55
  151. package/api/doc/picoflow.constant.md +0 -55
  152. package/api/doc/picoflow.derivation.md +0 -55
  153. package/api/doc/picoflow.effect.md +0 -55
  154. package/api/doc/picoflow.flowarray._constructor_.md +0 -49
  155. package/api/doc/picoflow.flowarray._lastaction.md +0 -13
  156. package/api/doc/picoflow.flowarray.clear.md +0 -17
  157. package/api/doc/picoflow.flowarray.dispose.md +0 -55
  158. package/api/doc/picoflow.flowarray.get.md +0 -19
  159. package/api/doc/picoflow.flowarray.length.md +0 -13
  160. package/api/doc/picoflow.flowarray.md +0 -273
  161. package/api/doc/picoflow.flowarray.pop.md +0 -17
  162. package/api/doc/picoflow.flowarray.push.md +0 -53
  163. package/api/doc/picoflow.flowarray.set.md +0 -53
  164. package/api/doc/picoflow.flowarray.setitem.md +0 -69
  165. package/api/doc/picoflow.flowarray.shift.md +0 -17
  166. package/api/doc/picoflow.flowarray.splice.md +0 -85
  167. package/api/doc/picoflow.flowarray.unshift.md +0 -53
  168. package/api/doc/picoflow.flowarrayaction.md +0 -37
  169. package/api/doc/picoflow.flowconstant._constructor_.md +0 -49
  170. package/api/doc/picoflow.flowconstant.get.md +0 -25
  171. package/api/doc/picoflow.flowconstant.md +0 -88
  172. package/api/doc/picoflow.flowderivation._constructor_.md +0 -49
  173. package/api/doc/picoflow.flowderivation.get.md +0 -23
  174. package/api/doc/picoflow.flowderivation.md +0 -86
  175. package/api/doc/picoflow.flowdisposable.dispose.md +0 -55
  176. package/api/doc/picoflow.flowdisposable.md +0 -43
  177. package/api/doc/picoflow.floweffect._constructor_.md +0 -54
  178. package/api/doc/picoflow.floweffect.dispose.md +0 -21
  179. package/api/doc/picoflow.floweffect.disposed.md +0 -13
  180. package/api/doc/picoflow.floweffect.md +0 -131
  181. package/api/doc/picoflow.flowgetter.md +0 -15
  182. package/api/doc/picoflow.flowmap._lastdeleted.md +0 -21
  183. package/api/doc/picoflow.flowmap._lastset.md +0 -21
  184. package/api/doc/picoflow.flowmap.delete.md +0 -61
  185. package/api/doc/picoflow.flowmap.md +0 -133
  186. package/api/doc/picoflow.flowmap.setat.md +0 -77
  187. package/api/doc/picoflow.flowobservable.get.md +0 -19
  188. package/api/doc/picoflow.flowobservable.md +0 -68
  189. package/api/doc/picoflow.flowobservable.subscribe.md +0 -55
  190. package/api/doc/picoflow.flowresource._constructor_.md +0 -49
  191. package/api/doc/picoflow.flowresource.fetch.md +0 -27
  192. package/api/doc/picoflow.flowresource.get.md +0 -23
  193. package/api/doc/picoflow.flowresource.md +0 -100
  194. package/api/doc/picoflow.flowresourceasync._constructor_.md +0 -49
  195. package/api/doc/picoflow.flowresourceasync.fetch.md +0 -27
  196. package/api/doc/picoflow.flowresourceasync.get.md +0 -23
  197. package/api/doc/picoflow.flowresourceasync.md +0 -100
  198. package/api/doc/picoflow.flowsignal.dispose.md +0 -59
  199. package/api/doc/picoflow.flowsignal.disposed.md +0 -18
  200. package/api/doc/picoflow.flowsignal.md +0 -112
  201. package/api/doc/picoflow.flowsignal.trigger.md +0 -21
  202. package/api/doc/picoflow.flowstate.md +0 -52
  203. package/api/doc/picoflow.flowstate.set.md +0 -61
  204. package/api/doc/picoflow.flowstream._constructor_.md +0 -49
  205. package/api/doc/picoflow.flowstream.dispose.md +0 -21
  206. package/api/doc/picoflow.flowstream.get.md +0 -23
  207. package/api/doc/picoflow.flowstream.md +0 -100
  208. package/api/doc/picoflow.flowstreamasync._constructor_.md +0 -54
  209. package/api/doc/picoflow.flowstreamasync.dispose.md +0 -21
  210. package/api/doc/picoflow.flowstreamasync.get.md +0 -23
  211. package/api/doc/picoflow.flowstreamasync.md +0 -100
  212. package/api/doc/picoflow.flowstreamdisposer.md +0 -13
  213. package/api/doc/picoflow.flowstreamsetter.md +0 -13
  214. package/api/doc/picoflow.flowstreamupdater.md +0 -19
  215. package/api/doc/picoflow.flowwatcher.md +0 -15
  216. package/api/doc/picoflow.from.md +0 -55
  217. package/api/doc/picoflow.from_1.md +0 -55
  218. package/api/doc/picoflow.from_2.md +0 -55
  219. package/api/doc/picoflow.from_3.md +0 -55
  220. package/api/doc/picoflow.from_4.md +0 -55
  221. package/api/doc/picoflow.from_5.md +0 -55
  222. package/api/doc/picoflow.isdisposable.md +0 -55
  223. package/api/doc/picoflow.map.md +0 -59
  224. package/api/doc/picoflow.md +0 -544
  225. package/api/doc/picoflow.resource.md +0 -55
  226. package/api/doc/picoflow.resourceasync.md +0 -55
  227. package/api/doc/picoflow.signal.md +0 -19
  228. package/api/doc/picoflow.solidderivation._constructor_.md +0 -49
  229. package/api/doc/picoflow.solidderivation.get.md +0 -13
  230. package/api/doc/picoflow.solidderivation.md +0 -94
  231. package/api/doc/picoflow.solidgetter.md +0 -13
  232. package/api/doc/picoflow.solidobservable.get.md +0 -13
  233. package/api/doc/picoflow.solidobservable.md +0 -57
  234. package/api/doc/picoflow.solidresource._constructor_.md +0 -49
  235. package/api/doc/picoflow.solidresource.get.md +0 -13
  236. package/api/doc/picoflow.solidresource.latest.md +0 -13
  237. package/api/doc/picoflow.solidresource.md +0 -157
  238. package/api/doc/picoflow.solidresource.refetch.md +0 -13
  239. package/api/doc/picoflow.solidresource.state.md +0 -13
  240. package/api/doc/picoflow.solidstate._constructor_.md +0 -49
  241. package/api/doc/picoflow.solidstate.get.md +0 -13
  242. package/api/doc/picoflow.solidstate.md +0 -115
  243. package/api/doc/picoflow.solidstate.set.md +0 -13
  244. package/api/doc/picoflow.state.md +0 -55
  245. package/api/doc/picoflow.stream.md +0 -55
  246. package/api/doc/picoflow.streamasync.md +0 -55
  247. package/api/picoflow.public.api.md +0 -244
  248. package/api-extractor.json +0 -61
@@ -0,0 +1,371 @@
1
+ # Lifecycle
2
+
3
+ Understanding PicoFlow's internal execution model is key to mastering reactive programming. This guide walks through exactly what happens during creation, updates, and disposal using a concrete example.
4
+
5
+ ## The Example
6
+
7
+ Throughout this guide, we'll use this simple but complete example:
8
+
9
+ ```typescript
10
+ const $a = state(1)
11
+ const $b = state(2)
12
+ const $c = derivation((t) => $a.get(t) + $b.get(t))
13
+ effect((t) => console.log('C =', $c.get(t)))
14
+ ```
15
+
16
+ This example demonstrates:
17
+ - **Two states**: `$a` and `$b`
18
+ - **One derivation**: `$c` that computes the sum
19
+ - **One effect**: that logs the result
20
+
21
+ Let's see what happens at each stage of the lifecycle.
22
+
23
+ ## Creation Flow
24
+
25
+ When you run the example code, here's the exact sequence of events:
26
+
27
+ ### Step-by-Step
28
+
29
+ 1. **`state(1)` creates `$a`**
30
+ - A new `FlowState` instance is created
31
+ - Internal value is set to `1`
32
+ - No dependencies yet
33
+
34
+ 2. **`state(2)` creates `$b`**
35
+ - Another `FlowState` instance is created
36
+ - Internal value is set to `2`
37
+ - No dependencies yet
38
+
39
+ 3. **`derivation(...)` creates `$c`**
40
+ - A new `FlowDerivation` instance is created
41
+ - The compute function is stored but **NOT executed** (lazy evaluation)
42
+ - A `TrackingContext` is created for the derivation
43
+ - Still no computed value yet
44
+
45
+ 4. **`effect(...)` creates the effect**
46
+ - A new `FlowEffect` instance is created
47
+ - A `TrackingContext` is created for the effect
48
+ - **The effect executes immediately** (not lazy!)
49
+ - During execution:
50
+ - Effect calls `$c.get(t)`
51
+ - This triggers `$c` to initialize (first access)
52
+ - `$c` runs its compute function with its tracking context
53
+ - Compute calls `$a.get(t)` → returns `1`, registers `$a` as dependency of `$c`
54
+ - Compute calls `$b.get(t)` → returns `2`, registers `$b` as dependency of `$c`
55
+ - Compute returns `3`
56
+ - Effect's `$c.get(t)` returns `3`, registers `$c` as dependency of effect
57
+ - Effect logs: `"C = 3"`
58
+
59
+ ### Creation Sequence Diagram
60
+
61
+ ```mermaid
62
+ sequenceDiagram
63
+ participant User
64
+ participant $a as $a (State)
65
+ participant $b as $b (State)
66
+ participant $c as $c (Derivation)
67
+ participant Effect
68
+ participant Context
69
+
70
+ User->>$a: state(1)
71
+ activate $a
72
+ Note over $a: Store value: 1
73
+ deactivate $a
74
+
75
+ User->>$b: state(2)
76
+ activate $b
77
+ Note over $b: Store value: 2
78
+ deactivate $b
79
+
80
+ User->>$c: derivation((t) => ...)
81
+ activate $c
82
+ Note over $c: Store compute fn<br/>NOT executed yet<br/>(lazy)
83
+ deactivate $c
84
+
85
+ User->>Effect: effect((t) => ...)
86
+ activate Effect
87
+ Note over Effect: Create & execute<br/>immediately
88
+
89
+ Effect->>$c: get(t)
90
+ activate $c
91
+ Note over $c: First access!<br/>Initialize & compute
92
+
93
+ $c->>$a: get(t)
94
+ activate $a
95
+ $a-->>$c: 1
96
+ $a->>$c: Register as listener
97
+ Note over $a,$c: $c now depends on $a
98
+ deactivate $a
99
+
100
+ $c->>$b: get(t)
101
+ activate $b
102
+ $b-->>$c: 2
103
+ $b->>$c: Register as listener
104
+ Note over $b,$c: $c now depends on $b
105
+ deactivate $b
106
+
107
+ Note over $c: Compute: 1 + 2 = 3
108
+ $c-->>Effect: 3
109
+ $c->>Effect: Register as effect
110
+ Note over $c,Effect: Effect depends on $c
111
+ deactivate $c
112
+
113
+ Note over Effect: Log: "C = 3"
114
+ deactivate Effect
115
+ ```
116
+
117
+ **Key Insights:**
118
+ - States are simple: just store the value
119
+ - Derivations are **lazy**: they don't compute until accessed
120
+ - Effects are **eager**: they execute immediately on creation
121
+ - Dependencies are registered **during execution** through `.get(t)`
122
+
123
+ ## Update Flow
124
+
125
+ Now let's see what happens when we update `$a`:
126
+
127
+ ```typescript
128
+ $a.set(5)
129
+ ```
130
+
131
+ ### The Push-Pull Model
132
+
133
+ PicoFlow uses a "**push notification, pull computation**" model:
134
+
135
+ - **Push**: When a value changes, notifications are pushed to all dependents immediately
136
+ - **Pull**: Actual recomputation only happens when a value is accessed (pulled)
137
+
138
+ This is efficient because:
139
+ - Derivations that aren't currently needed don't recompute
140
+ - Multiple state changes can batch before triggering computation
141
+ - Only the necessary chain of dependencies is recomputed
142
+
143
+ ### Step-by-Step
144
+
145
+ 1. **`$a.set(5)` is called**
146
+ - `$a` checks if the value changed: `5 !== 1` ✓
147
+ - `$a` updates its internal value: `1 → 5`
148
+ - `$a` notifies all its dependents
149
+
150
+ 2. **`$a` notifies its dependents**
151
+ - `$a` sends notifications to all listeners (includes `$c`)
152
+ - `$c` receives the notification
153
+
154
+ 3. **`$c` receives notification**
155
+ - `$c` marks itself as needing recomputation
156
+ - **Does NOT recompute yet!** (lazy evaluation)
157
+ - `$c` propagates the notification to its dependents
158
+
159
+ 4. **`$c` notifies its dependents**
160
+ - `$c` sends notifications to all effects (includes our effect)
161
+ - The effect is scheduled to execute
162
+
163
+ 5. **Effect executes**
164
+ - Effect runs its function with tracking context
165
+ - Calls `$c.get(t)`
166
+
167
+ 6. **`$c` recomputes (pull)**
168
+ - `$c.get(t)` detects that recomputation is needed
169
+ - Clears old dependencies
170
+ - Runs compute function again
171
+ - Compute calls `$a.get(t)` → returns `5`
172
+ - Compute calls `$b.get(t)` → returns `2`
173
+ - Computes new value: `5 + 2 = 7`
174
+ - Re-registers dependencies
175
+ - Returns `7`
176
+
177
+ 7. **Effect logs the result**
178
+ - Effect receives `7` from `$c.get(t)`
179
+ - Logs: `"C = 7"`
180
+
181
+ ### Update Sequence Diagram
182
+
183
+ ```mermaid
184
+ sequenceDiagram
185
+ participant User
186
+ participant $a as $a (State)
187
+ participant $c as $c (Derivation)
188
+ participant Effect
189
+
190
+ User->>$a: set(5)
191
+ activate $a
192
+ Note over $a: Check: 5 !== 1 ✓<br/>Update: 1 → 5
193
+
194
+ $a->>$c: notify
195
+ activate $c
196
+ Note over $c: Mark as needs<br/>recomputation<br/>NO recompute yet!
197
+
198
+ $c->>Effect: notify
199
+ deactivate $c
200
+ deactivate $a
201
+
202
+ activate Effect
203
+ Note over Effect: Execute function
204
+
205
+ Effect->>$c: get(t)
206
+ activate $c
207
+ Note over $c: Recomputation<br/>needed? YES
208
+
209
+ Note over $c: Recompute
210
+ activate $c
211
+ Note over $c: Clear old deps
212
+
213
+ $c->>$a: get(t)
214
+ activate $a
215
+ $a-->>$c: 5
216
+ deactivate $a
217
+
218
+ $c->>$b: get(t)
219
+ activate $b
220
+ $b-->>$c: 2
221
+ deactivate $b
222
+
223
+ Note over $c: Compute: 5 + 2 = 7<br/>Re-register deps
224
+ deactivate $c
225
+
226
+ $c-->>Effect: 7
227
+ deactivate $c
228
+
229
+ Note over Effect: Log: "C = 7"
230
+ deactivate Effect
231
+ ```
232
+
233
+ **Key Insights:**
234
+ - **Notifications are pushed** immediately when state changes
235
+ - **Derivations mark as dirty** but don't recompute until needed
236
+ - **Effects execute immediately** when notified
237
+ - **Recomputation is pulled** when effects access derivations
238
+ - **Dependencies are re-registered** on each execution (dynamic tracking)
239
+
240
+ ## Disposal Flow
241
+
242
+ Finally, let's see what happens when we dispose a primitive:
243
+
244
+ ```typescript
245
+ $a.dispose()
246
+ ```
247
+
248
+ ### Step-by-Step
249
+
250
+ 1. **`$a.dispose()` is called**
251
+ - `$a` checks if already disposed (throws if yes)
252
+ - Iterates through all listeners (dependents like `$c`)
253
+ - Iterates through all effects (none in this case)
254
+
255
+ 2. **Cleanup listeners**
256
+ - For each listener, calls `listener.dispose()`
257
+ - This triggers `$c.dispose()`
258
+
259
+ 3. **`$c.dispose()` cascades**
260
+ - `$c` iterates through its listeners (none)
261
+ - `$c` iterates through its effects (includes our effect)
262
+ - Calls `effect.dispose()`
263
+
264
+ 4. **Effect cleanup**
265
+ - Effect unregisters from all its dependencies (`$c`)
266
+ - Effect marks itself as disposed
267
+ - Future notifications won't trigger this effect
268
+
269
+ 5. **State cleanup**
270
+ - `$a` unregisters from all its listeners
271
+ - `$a` marks itself as disposed
272
+ - Future attempts to use `$a` will throw errors
273
+
274
+ 6. **Result**
275
+ - The entire dependency graph is cleaned up
276
+ - Memory is freed
277
+ - No more reactions will occur
278
+
279
+ ### Disposal Sequence Diagram
280
+
281
+ ```mermaid
282
+ sequenceDiagram
283
+ participant User
284
+ participant $a as $a (State)
285
+ participant $c as $c (Derivation)
286
+ participant Effect
287
+
288
+ User->>$a: dispose()
289
+ activate $a
290
+ Note over $a: Check if disposed<br/>Iterate listeners
291
+
292
+ $a->>$c: dispose()
293
+ activate $c
294
+ Note over $c: Iterate effects
295
+
296
+ $c->>Effect: dispose()
297
+ activate Effect
298
+
299
+ Effect->>$c: Unregister
300
+ Note over Effect,$c: Remove dependency
301
+
302
+ Note over Effect: Mark disposed<br/>Stop running
303
+ deactivate Effect
304
+
305
+ $c->>$a: Unregister
306
+ Note over $c,$a: Remove dependency
307
+
308
+ Note over $c: Mark disposed
309
+ deactivate $c
310
+
311
+ Note over $a: Mark disposed<br/>Clean up listeners
312
+ deactivate $a
313
+
314
+ Note over User,Effect: All cleaned up!<br/>Memory freed
315
+ ```
316
+
317
+ **Key Insights:**
318
+ - **Disposal cascades** through the dependency graph
319
+ - **Dependents are disposed first** (effects before derivations before states)
320
+ - **All registrations are cleaned up** to prevent memory leaks
321
+ - **Disposed primitives throw errors** if you try to use them
322
+ - **Order matters**: dispose dependents before dependencies when doing manual cleanup
323
+
324
+ ## Practical Implications
325
+
326
+ Understanding these flows helps you:
327
+
328
+ ### 1. Optimize Performance
329
+
330
+ ```typescript
331
+ // Derivation won't compute if effect is disposed
332
+ const $expensive = derivation((t) => {
333
+ return expensiveCalculation($data.get(t))
334
+ })
335
+
336
+ const fx = effect((t) => {
337
+ if (shouldDisplay) {
338
+ display($expensive.get(t)) // Only computes when accessed
339
+ }
340
+ })
341
+
342
+ // When not needed, just dispose the effect
343
+ fx.dispose() // $expensive stops computing
344
+ ```
345
+
346
+ ### 2. Debug Dependency Issues
347
+
348
+ ```typescript
349
+ // If logs don't appear, check:
350
+ // 1. Is the effect created? (runs immediately)
351
+ // 2. Are you using .get(t)? (not .pick())
352
+ // 3. Is anything disposed?
353
+
354
+ effect((t) => {
355
+ console.log('Effect created') // Should log immediately
356
+ console.log('Value:', $state.get(t)) // Creates dependency
357
+ })
358
+ ```
359
+
360
+ ### 3. Avoid Memory Leaks
361
+
362
+ ```typescript
363
+ // Always dispose effects when done
364
+ const disposables: FlowDisposable[] = []
365
+
366
+ disposables.push(effect((t) => { /* ... */ }))
367
+ disposables.push(effect((t) => { /* ... */ }))
368
+
369
+ // Clean up
370
+ disposables.forEach(d => d.dispose())
371
+ ```