@ersbeth/picoflow 0.2.4 → 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 +610 -436
  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 -23
  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,400 @@
1
+ # Arrays
2
+
3
+ PicoFlow provides reactive arrays with **fine-grained tracking**. Instead of reacting to the entire array changing, you can react to specific operations like pushing, popping, or splicing individual items.
4
+
5
+ Imagine you have a list of 1000 todos. In a naive reactive system, every time you add, remove, or update a single todo, the entire list re-renders. **Inefficient!** With PicoFlow's reactive arrays, you can track specific operations and only update what changed.
6
+
7
+ ### Key Characteristics
8
+
9
+ - **Fine-grained reactivity**: Track individual operations (push, pop, splice, etc.) separately
10
+ - **Multiple tracking levels**: Track the whole array or specific operations
11
+ - **Native Array**: Uses JavaScript's native `Array<T>` internally
12
+ - **Operation-specific signal**: `$lastAction` for granular tracking of all operations
13
+ - **Disposable**: Can be disposed to clean up resources
14
+
15
+ ## When to Use Arrays
16
+
17
+ Use arrays when you need to:
18
+
19
+ - ✅ Track large collections with fine-grained updates
20
+ - ✅ React to specific operations (additions, removals, updates) separately
21
+ - ✅ Manage ordered collections where individual item operations matter
22
+ - ✅ Optimize performance by avoiding full array re-processing
23
+ - ✅ Animate or handle UI updates for specific changes
24
+
25
+ Don't use arrays when:
26
+
27
+ - ❌ You have a small, simple list (use `state` instead)
28
+ - ❌ You don't need fine-grained tracking (use `state` with an array)
29
+ - ❌ You need key-value operations (use `map` instead)
30
+ - ❌ The collection is rarely modified (regular state might be simpler)
31
+
32
+ ## Creating Arrays
33
+
34
+ Creating a reactive array is straightforward:
35
+
36
+ ```typescript
37
+ import { array } from '@ersbeth/picoflow'
38
+
39
+ // Create with initial values
40
+ const $todos = array([
41
+ { id: 1, text: 'Learn PicoFlow', done: false },
42
+ { id: 2, text: 'Build app', done: false }
43
+ ])
44
+
45
+ // Create empty
46
+ const $items = array<string>()
47
+ ```
48
+
49
+ ## Using Arrays
50
+
51
+ Arrays provide multiple ways to track changes and perform operations.
52
+
53
+ ### Array Operations
54
+
55
+ Arrays provide several operations: `set()`, `setItem()`, `push()`, `pop()`, `unshift()`, `shift()`, `splice()`, and `clear()`.
56
+
57
+ ```typescript
58
+ const $list = array<number>([])
59
+
60
+ // Replace entire array
61
+ $list.set([1, 2, 3])
62
+
63
+ // Replace item at index
64
+ $list.setItem(0, 10)
65
+
66
+ // Add to end
67
+ $list.push(4)
68
+
69
+ // Add to start
70
+ $list.unshift(0)
71
+
72
+ // Remove from end
73
+ $list.pop()
74
+
75
+ // Remove from start
76
+ $list.shift()
77
+
78
+ // Splice (remove/add at index)
79
+ $list.splice(1, 1, 99) // Remove 1 item at index 1, add 99
80
+
81
+ // Clear all
82
+ $list.clear()
83
+
84
+ // Read (reactive)
85
+ effect((t) => {
86
+ const items = $list.get(t)
87
+ // Track entire array
88
+ })
89
+
90
+ // Read (non-reactive)
91
+ const snapshot = $list.pick()
92
+ ```
93
+
94
+ **Important**:
95
+ - `setItem(index, item)` throws an error if the index is out of bounds
96
+ - `push(item)` only accepts a single item
97
+ - `splice(start, deleteCount, ...items)` accepts multiple items to add
98
+
99
+ ### Whole Array Tracking with `.get(t)`
100
+
101
+ Track when the entire array changes (any operation):
102
+
103
+ ```typescript
104
+ import { array, effect } from '@ersbeth/picoflow'
105
+
106
+ const $items = array([1, 2, 3])
107
+
108
+ effect((t) => {
109
+ const items = $items.get(t) // Track all changes
110
+ console.log('Array changed:', items)
111
+ })
112
+
113
+ $items.push(4) // Logs: "Array changed: [1,2,3,4]"
114
+ $items.pop() // Logs: "Array changed: [1,2,3]"
115
+ $items.splice(1, 1) // Logs: "Array changed: [1,3]"
116
+ ```
117
+
118
+ Use `.get(t)` when you need the entire array's current state. It returns a copy of the array.
119
+
120
+ ### Fine-Grained: Track Operations
121
+
122
+ Track specific operations with `$lastAction`:
123
+
124
+ ```typescript
125
+ const $items = array<number>([])
126
+
127
+ effect((t) => {
128
+ const action = $items.$lastAction.get(t)
129
+ if (!action) return
130
+
131
+ switch (action.type) {
132
+ case 'push':
133
+ console.log('Pushed:', action.item)
134
+ break
135
+ case 'pop':
136
+ console.log('Popped')
137
+ break
138
+ case 'splice':
139
+ console.log('Splice at', action.start, ':', action.deleteCount, 'deleted,', action.items.length, 'added')
140
+ break
141
+ case 'setItem':
142
+ console.log('Set item at', action.index, 'to', action.item)
143
+ break
144
+ // ... other operations
145
+ }
146
+ })
147
+
148
+ $items.push(1) // Logs: "Pushed: 1"
149
+ $items.push(2) // Logs: "Pushed: 2"
150
+ $items.pop() // Logs: "Popped"
151
+ $items.splice(0, 1) // Logs: "Splice at 0: 1 deleted, 0 added"
152
+ ```
153
+
154
+ ## Array Action Types
155
+
156
+ The `$lastAction` signal contains information about the last operation:
157
+
158
+ ```typescript
159
+ type FlowArrayAction<T> =
160
+ | { type: 'set'; items: T[] }
161
+ | { type: 'setItem'; index: number; item: T }
162
+ | { type: 'push'; item: T }
163
+ | { type: 'pop' }
164
+ | { type: 'shift' }
165
+ | { type: 'unshift'; item: T }
166
+ | { type: 'splice'; start: number; deleteCount: number; items: T[] }
167
+ | { type: 'clear' }
168
+ ```
169
+
170
+ ## Lifecycle
171
+
172
+ When you create an effect that tracks an array:
173
+
174
+ 1. **Registration**: The array registers the effect as a watcher
175
+ 2. **Operation**: When you call `push()`, `pop()`, `splice()`, etc., the array updates internally
176
+ 3. **Signal Update**: The `$lastAction` signal is updated with the operation details
177
+ 4. **Notification**: All watching effects are scheduled to run
178
+ 5. **Re-execution**: Each watching effect re-executes its function
179
+
180
+ ```mermaid
181
+ sequenceDiagram
182
+ participant User
183
+ participant Array as $todos (Array)
184
+ participant Signal as $lastAction
185
+ participant Effect
186
+
187
+ Note over User,Effect: 1. Setup Phase
188
+ User->>Effect: Create effect
189
+ activate Effect
190
+ Effect->>Array: get(t)
191
+ Note over Array: Register Effect as watcher
192
+ Effect->>Signal: get(t)
193
+ Note over Signal: Register Effect as watcher
194
+ Effect->>Effect: Execute function
195
+ Note over Effect: Initial render
196
+ deactivate Effect
197
+
198
+ Note over User,Effect: 2. Operation Phase
199
+ User->>Array: push(todo)
200
+ activate Array
201
+ Note over Array: Update internal array
202
+ Array->>Signal: set({ type: 'push', item: todo })
203
+ activate Signal
204
+ Note over Signal: Notify watchers
205
+ Signal->>Effect: Schedule execution
206
+ deactivate Signal
207
+ Array->>Array: Notify whole array watchers
208
+ Array->>Effect: Schedule execution
209
+ deactivate Array
210
+
211
+ activate Effect
212
+ Note over Effect: Re-execute function
213
+ Effect->>Signal: get(t)
214
+ Signal-->>Effect: { type: 'push', item: todo }
215
+ Effect->>Effect: Handle new todo
216
+ Note over Effect: Update UI
217
+ deactivate Effect
218
+ ```
219
+
220
+ ## Best Practices
221
+
222
+ ### Choose the Right Granularity
223
+
224
+ ```typescript
225
+ // ✅ Use fine-grained for large arrays
226
+ const $todos = array<Todo>([...1000 todos...])
227
+ effect((t) => {
228
+ const action = $todos.$lastAction.get(t)
229
+ if (action) {
230
+ // Handle specific change
231
+ }
232
+ })
233
+
234
+ // ✅ Use coarse-grained for small arrays
235
+ const $settings = state(['dark', 'en', 'large'])
236
+ effect((t) => {
237
+ const settings = $settings.get(t)
238
+ // Re-apply all settings (cheap for 3 items)
239
+ })
240
+ ```
241
+
242
+ ### Combine for Best Results
243
+
244
+ ```typescript
245
+ // Fine-grained for UI updates
246
+ effect((t) => {
247
+ const action = $items.$lastAction.get(t)
248
+ if (action) {
249
+ updateUIIncremental(action)
250
+ }
251
+ })
252
+
253
+ // Coarse-grained for totals
254
+ const $total = derivation((t) => {
255
+ return $items.get(t).reduce((sum, item) => sum + item.value, 0)
256
+ })
257
+ ```
258
+
259
+ ### Handle All Action Types
260
+
261
+ ```typescript
262
+ effect((t) => {
263
+ const action = $items.$lastAction.get(t)
264
+ if (!action) return
265
+
266
+ switch (action.type) {
267
+ case 'push':
268
+ // Handle push
269
+ break
270
+ case 'pop':
271
+ // Handle pop
272
+ break
273
+ case 'splice':
274
+ // Handle splice
275
+ break
276
+ case 'setItem':
277
+ // Handle setItem
278
+ break
279
+ case 'clear':
280
+ // Handle clear
281
+ break
282
+ // Don't forget any cases!
283
+ }
284
+ })
285
+ ```
286
+
287
+ ### Dispose Items Properly
288
+
289
+ ```typescript
290
+ // When removing disposable items
291
+ effect((t) => {
292
+ const action = $resources.$lastAction.get(t)
293
+ if (action && action.type === 'splice') {
294
+ // Dispose removed items (they're already disposed by the array)
295
+ // But you might want to do additional cleanup
296
+ }
297
+ })
298
+ ```
299
+
300
+ Arrays automatically dispose disposable items when they are removed, but you can add additional cleanup logic if needed.
301
+
302
+ ## Common Pitfalls
303
+
304
+ ### Forgetting to Handle Nulls
305
+
306
+ **Problem**: The `$lastAction` signal can be `null` initially or after certain operations.
307
+
308
+ ```typescript
309
+ // ❌ Can be null initially
310
+ effect((t) => {
311
+ const action = $items.$lastAction.get(t)
312
+ console.log(action.type) // Error if null!
313
+ })
314
+ ```
315
+
316
+ **Solution**: Always check for null:
317
+
318
+ ```typescript
319
+ // ✅ Check for null
320
+ effect((t) => {
321
+ const action = $items.$lastAction.get(t)
322
+ if (action) {
323
+ console.log(action.type)
324
+ }
325
+ })
326
+ ```
327
+
328
+ ### Using Wrong Tracking
329
+
330
+ **Problem**: Tracking the entire array when you only need specific operations.
331
+
332
+ ```typescript
333
+ // ❌ Tracks entire array when you only need additions
334
+ effect((t) => {
335
+ const items = $items.get(t) // Runs on ALL changes
336
+ const lastItem = items[items.length - 1]
337
+ animateNewItem(lastItem)
338
+ })
339
+ ```
340
+
341
+ **Solution**: Track only what you need:
342
+
343
+ ```typescript
344
+ // ✅ Track only pushes
345
+ effect((t) => {
346
+ const action = $items.$lastAction.get(t)
347
+ if (action && action.type === 'push') {
348
+ animateNewItem(action.item)
349
+ }
350
+ })
351
+ ```
352
+
353
+ ### Mutating Retrieved Arrays
354
+
355
+ **Problem**: Mutating the array directly instead of using reactive methods.
356
+
357
+ ```typescript
358
+ // ❌ Mutating the array
359
+ const items = $items.pick()
360
+ items.push(newItem) // Doesn't update reactive array!
361
+ ```
362
+
363
+ **Solution**: Use reactive methods:
364
+
365
+ ```typescript
366
+ // ✅ Use reactive methods
367
+ $items.push(newItem)
368
+ ```
369
+
370
+ ### Using Wrong Action Properties
371
+
372
+ **Problem**: Using incorrect property names from action objects.
373
+
374
+ ```typescript
375
+ // ❌ Wrong property names
376
+ effect((t) => {
377
+ const action = $items.$lastAction.get(t)
378
+ if (action && action.type === 'push') {
379
+ console.log(action.value) // Error! Should be action.item
380
+ }
381
+ if (action && action.type === 'splice') {
382
+ console.log(action.index) // Error! Should be action.start
383
+ }
384
+ })
385
+ ```
386
+
387
+ **Solution**: Use correct property names:
388
+
389
+ ```typescript
390
+ // ✅ Correct property names
391
+ effect((t) => {
392
+ const action = $items.$lastAction.get(t)
393
+ if (action && action.type === 'push') {
394
+ console.log(action.item) // Correct
395
+ }
396
+ if (action && action.type === 'splice') {
397
+ console.log(action.start) // Correct
398
+ }
399
+ })
400
+ ```