@ersbeth/picoflow 1.1.1 → 2.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.
- package/.vscode/settings.json +3 -3
- package/CHANGELOG.md +43 -0
- package/README.md +2 -18
- package/biome.json +45 -35
- package/dist/picoflow.js +857 -1528
- package/dist/types/api/base/flowDisposable.d.ts +41 -0
- package/dist/types/api/base/flowDisposable.d.ts.map +1 -0
- package/dist/types/api/base/flowObservable.d.ts +27 -0
- package/dist/types/api/base/flowObservable.d.ts.map +1 -0
- package/dist/types/api/base/flowSubscribable.d.ts +79 -0
- package/dist/types/api/base/flowSubscribable.d.ts.map +1 -0
- package/dist/types/api/base/flowTracker.d.ts +8 -0
- package/dist/types/api/base/flowTracker.d.ts.map +1 -0
- package/dist/types/api/base/index.d.ts +5 -0
- package/dist/types/api/base/index.d.ts.map +1 -0
- package/dist/types/api/index.d.ts +3 -0
- package/dist/types/api/index.d.ts.map +1 -0
- package/dist/types/api/nodes/async/flowConstantAsync.d.ts +31 -0
- package/dist/types/api/nodes/async/flowConstantAsync.d.ts.map +1 -0
- package/dist/types/api/nodes/async/flowDerivationAsync.d.ts +37 -0
- package/dist/types/api/nodes/async/flowDerivationAsync.d.ts.map +1 -0
- package/dist/types/api/nodes/async/flowStateAsync.d.ts +41 -0
- package/dist/types/api/nodes/async/flowStateAsync.d.ts.map +1 -0
- package/dist/types/api/nodes/async/flowWritableDerivationAsync.d.ts +30 -0
- package/dist/types/api/nodes/async/flowWritableDerivationAsync.d.ts.map +1 -0
- package/dist/types/{flow → api}/nodes/async/index.d.ts +1 -2
- package/dist/types/api/nodes/async/index.d.ts.map +1 -0
- package/dist/types/api/nodes/collections/flowArray.d.ts +134 -0
- package/dist/types/api/nodes/collections/flowArray.d.ts.map +1 -0
- package/dist/types/api/nodes/collections/flowMap.d.ts +98 -0
- package/dist/types/api/nodes/collections/flowMap.d.ts.map +1 -0
- package/dist/types/api/nodes/collections/index.d.ts.map +1 -0
- package/dist/types/api/nodes/flowEffect.d.ts +28 -0
- package/dist/types/api/nodes/flowEffect.d.ts.map +1 -0
- package/dist/types/api/nodes/flowSignal.d.ts +25 -0
- package/dist/types/api/nodes/flowSignal.d.ts.map +1 -0
- package/dist/types/api/nodes/flowValue.d.ts +35 -0
- package/dist/types/api/nodes/flowValue.d.ts.map +1 -0
- package/dist/types/api/nodes/index.d.ts +8 -0
- package/dist/types/api/nodes/index.d.ts.map +1 -0
- package/dist/types/api/nodes/sync/flowConstant.d.ts +29 -0
- package/dist/types/api/nodes/sync/flowConstant.d.ts.map +1 -0
- package/dist/types/api/nodes/sync/flowDerivation.d.ts +36 -0
- package/dist/types/api/nodes/sync/flowDerivation.d.ts.map +1 -0
- package/dist/types/api/nodes/sync/flowState.d.ts +39 -0
- package/dist/types/api/nodes/sync/flowState.d.ts.map +1 -0
- package/dist/types/api/nodes/sync/flowWritableDerivation.d.ts +28 -0
- package/dist/types/api/nodes/sync/flowWritableDerivation.d.ts.map +1 -0
- package/dist/types/{flow → api}/nodes/sync/index.d.ts +1 -2
- package/dist/types/api/nodes/sync/index.d.ts.map +1 -0
- package/dist/types/api/nodes/utils.d.ts +22 -0
- package/dist/types/api/nodes/utils.d.ts.map +1 -0
- package/dist/types/base/disposable.d.ts +11 -0
- package/dist/types/base/disposable.d.ts.map +1 -0
- package/dist/types/base/executionStack.d.ts +14 -0
- package/dist/types/base/executionStack.d.ts.map +1 -0
- package/dist/types/base/index.d.ts +6 -0
- package/dist/types/base/index.d.ts.map +1 -0
- package/dist/types/base/node.d.ts +27 -0
- package/dist/types/base/node.d.ts.map +1 -0
- package/dist/types/base/observable.d.ts +37 -0
- package/dist/types/base/observable.d.ts.map +1 -0
- package/dist/types/base/observer.d.ts +25 -0
- package/dist/types/base/observer.d.ts.map +1 -0
- package/dist/types/converters/index.d.ts +2 -0
- package/dist/types/converters/index.d.ts.map +1 -0
- package/dist/types/converters/solid.d.ts +46 -0
- package/dist/types/converters/solid.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -63
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/nodes/arrayNode.d.ts +2 -0
- package/dist/types/nodes/arrayNode.d.ts.map +1 -0
- package/dist/types/nodes/effectNode.d.ts +2 -0
- package/dist/types/nodes/effectNode.d.ts.map +1 -0
- package/dist/types/nodes/index.d.ts +9 -0
- package/dist/types/nodes/index.d.ts.map +1 -0
- package/dist/types/nodes/mapNode.d.ts +2 -0
- package/dist/types/nodes/mapNode.d.ts.map +1 -0
- package/dist/types/nodes/signalNode.d.ts +2 -0
- package/dist/types/nodes/signalNode.d.ts.map +1 -0
- package/dist/types/nodes/valueAsyncNode.d.ts +2 -0
- package/dist/types/nodes/valueAsyncNode.d.ts.map +1 -0
- package/dist/types/nodes/valueNode.d.ts +2 -0
- package/dist/types/nodes/valueNode.d.ts.map +1 -0
- package/dist/types/nodes/valueSyncNode.d.ts +2 -0
- package/dist/types/nodes/valueSyncNode.d.ts.map +1 -0
- package/dist/types/schedulers/asyncResolver.d.ts +2 -0
- package/dist/types/schedulers/asyncResolver.d.ts.map +1 -0
- package/dist/types/schedulers/asyncScheduler.d.ts +2 -0
- package/dist/types/schedulers/asyncScheduler.d.ts.map +1 -0
- package/dist/types/schedulers/index.d.ts +5 -0
- package/dist/types/schedulers/index.d.ts.map +1 -0
- package/dist/types/schedulers/pendingError.d.ts +2 -0
- package/dist/types/schedulers/pendingError.d.ts.map +1 -0
- package/dist/types/schedulers/scheduler.d.ts +2 -0
- package/dist/types/schedulers/scheduler.d.ts.map +1 -0
- package/dist/types/schedulers/syncResolver.d.ts +2 -0
- package/dist/types/schedulers/syncResolver.d.ts.map +1 -0
- package/dist/types/schedulers/syncScheduler.d.ts +2 -0
- package/dist/types/schedulers/syncScheduler.d.ts.map +1 -0
- package/docs/.vitepress/config.mts +128 -93
- package/docs/api/functions/array.md +14 -37
- package/docs/api/functions/constant.md +13 -25
- package/docs/api/functions/constantAsync.md +69 -0
- package/docs/api/functions/derivation.md +14 -33
- package/docs/api/functions/derivationAsync.md +34 -0
- package/docs/api/functions/from.md +62 -153
- package/docs/api/functions/isDisposable.md +8 -30
- package/docs/api/functions/map.md +15 -36
- package/docs/api/functions/signal.md +8 -23
- package/docs/api/functions/state.md +43 -23
- package/docs/api/functions/stateAsync.md +69 -0
- package/docs/api/functions/subscribe.md +40 -0
- package/docs/api/functions/writableDerivation.md +33 -0
- package/docs/api/functions/writableDerivationAsync.md +34 -0
- package/docs/api/index.md +45 -102
- package/docs/api/interfaces/FlowArray.md +439 -0
- package/docs/api/interfaces/FlowConstant.md +220 -0
- package/docs/api/interfaces/FlowConstantAsync.md +221 -0
- package/docs/api/interfaces/FlowDerivation.md +241 -0
- package/docs/api/interfaces/FlowDerivationAsync.md +242 -0
- package/docs/api/interfaces/FlowDisposable.md +32 -38
- package/docs/api/interfaces/FlowEffect.md +64 -0
- package/docs/api/interfaces/FlowMap.md +374 -0
- package/docs/api/interfaces/FlowObservable.md +155 -0
- package/docs/api/interfaces/FlowSignal.md +156 -0
- package/docs/api/interfaces/FlowState.md +269 -0
- package/docs/api/interfaces/FlowStateAsync.md +268 -0
- package/docs/api/interfaces/FlowSubscribable.md +55 -0
- package/docs/api/interfaces/FlowTracker.md +61 -0
- package/docs/api/interfaces/FlowValue.md +222 -0
- package/docs/api/interfaces/FlowWritableDerivation.md +292 -0
- package/docs/api/interfaces/FlowWritableDerivationAsync.md +293 -0
- package/docs/api/type-aliases/DerivationFunction.md +28 -0
- package/docs/api/type-aliases/DerivationFunctionAsync.md +28 -0
- package/docs/api/type-aliases/FlowArrayAction.md +19 -8
- package/docs/api/type-aliases/FlowDataTracker.md +33 -0
- package/docs/api/type-aliases/FlowMapAction.md +48 -0
- package/docs/api/type-aliases/FlowOnDataListener.md +33 -0
- package/docs/api/type-aliases/FlowOnErrorListener.md +27 -0
- package/docs/api/type-aliases/FlowOnPendingListener.md +21 -0
- package/docs/api/type-aliases/FlowReadonly.md +22 -0
- package/docs/api/type-aliases/InitFunction.md +21 -0
- package/docs/api/type-aliases/InitFunctionAsync.md +21 -0
- package/docs/api/type-aliases/NotPromise.md +6 -3
- package/docs/api/type-aliases/UpdateFunction.md +27 -0
- package/docs/api/type-aliases/UpdateFunctionAsync.md +27 -0
- package/docs/api/typedoc-sidebar.json +1 -81
- package/docs/examples/examples.md +0 -2
- package/docs/guide/advanced/architecture.md +1234 -0
- package/docs/guide/advanced/migration-v2.md +204 -0
- package/docs/guide/advanced/solidjs.md +2 -88
- package/docs/guide/introduction/concepts.md +4 -3
- package/docs/guide/introduction/conventions.md +2 -33
- package/docs/guide/introduction/getting-started.md +28 -23
- package/docs/guide/introduction/lifecycle.md +16 -19
- package/docs/guide/primitives/array.md +102 -216
- package/docs/guide/primitives/constant.md +39 -212
- package/docs/guide/primitives/derivations.md +55 -122
- package/docs/guide/primitives/effects.md +155 -241
- package/docs/guide/primitives/map.md +64 -186
- package/docs/guide/primitives/overview.md +45 -128
- package/docs/guide/primitives/signal.md +51 -88
- package/docs/guide/primitives/state.md +34 -130
- package/package.json +56 -60
- package/src/api/base/flowDisposable.ts +44 -0
- package/src/api/base/flowObservable.ts +28 -0
- package/src/api/base/flowSubscribable.ts +87 -0
- package/src/api/base/flowTracker.ts +7 -0
- package/src/api/base/index.ts +4 -0
- package/src/{flow → api}/index.ts +0 -1
- package/src/api/nodes/async/flowConstantAsync.ts +36 -0
- package/src/api/nodes/async/flowDerivationAsync.ts +42 -0
- package/src/api/nodes/async/flowStateAsync.ts +47 -0
- package/src/api/nodes/async/flowWritableDerivationAsync.ts +33 -0
- package/src/{flow → api}/nodes/async/index.ts +1 -2
- package/src/api/nodes/collections/flowArray.ts +155 -0
- package/src/api/nodes/collections/flowMap.ts +115 -0
- package/src/api/nodes/flowEffect.ts +42 -0
- package/src/api/nodes/flowSignal.ts +28 -0
- package/src/api/nodes/flowValue.ts +36 -0
- package/src/api/nodes/index.ts +7 -0
- package/src/api/nodes/sync/flowConstant.ts +33 -0
- package/src/api/nodes/sync/flowDerivation.ts +41 -0
- package/src/api/nodes/sync/flowState.ts +45 -0
- package/src/api/nodes/sync/flowWritableDerivation.ts +31 -0
- package/src/{flow → api}/nodes/sync/index.ts +1 -2
- package/src/api/nodes/utils.ts +22 -0
- package/src/base/disposable.ts +18 -0
- package/src/base/executionStack.ts +42 -0
- package/src/base/index.ts +5 -0
- package/src/base/node.ts +98 -0
- package/src/base/observable.ts +87 -0
- package/src/base/observer.ts +51 -0
- package/src/converters/index.ts +1 -0
- package/src/converters/solid.ts +109 -0
- package/src/index.ts +2 -64
- package/src/nodes/arrayNode.ts +172 -0
- package/src/nodes/effectNode.ts +59 -0
- package/src/nodes/index.ts +8 -0
- package/src/nodes/mapNode.ts +127 -0
- package/src/nodes/signalNode.ts +21 -0
- package/src/nodes/valueAsyncNode.ts +88 -0
- package/src/nodes/valueNode.ts +144 -0
- package/src/nodes/valueSyncNode.ts +128 -0
- package/src/schedulers/asyncResolver.ts +78 -0
- package/src/schedulers/asyncScheduler.ts +66 -0
- package/src/schedulers/index.ts +4 -0
- package/src/schedulers/pendingError.ts +13 -0
- package/src/schedulers/scheduler.ts +9 -0
- package/src/schedulers/syncResolver.ts +69 -0
- package/src/schedulers/syncScheduler.ts +55 -0
- package/test/base/pendingError.test.ts +67 -0
- package/test/converters/solid.derivation.browser.test.tsx +69 -0
- package/test/converters/solid.node.test.ts +654 -0
- package/test/converters/solid.state.browser.test.tsx +1592 -0
- package/test/reactivity/flowSignal.test.ts +226 -0
- package/test/reactivity/nodes/async/asyncScheduler/asyncResolver.test.ts +593 -0
- package/test/reactivity/nodes/async/asyncScheduler/asyncScheduler.test.ts +317 -0
- package/test/reactivity/nodes/async/flowConstantAsync.test.ts +652 -0
- package/test/reactivity/nodes/async/flowDerivation.test.ts +898 -0
- package/test/reactivity/nodes/async/flowDerivationAsync.test.ts +1716 -0
- package/test/reactivity/nodes/async/flowStateAsync.test.ts +708 -0
- package/test/reactivity/nodes/async/flowWritableDerivationAsync.test.ts +614 -0
- package/test/reactivity/nodes/collections/flowArray.asyncStates.test.ts +1289 -0
- package/test/reactivity/nodes/collections/flowArray.scalars.test.ts +961 -0
- package/test/reactivity/nodes/collections/flowArray.states.test.ts +1035 -0
- package/test/reactivity/nodes/collections/flowMap.asyncStates.test.ts +960 -0
- package/test/reactivity/nodes/collections/flowMap.scalars.test.ts +775 -0
- package/test/reactivity/nodes/collections/flowMap.states.test.ts +958 -0
- package/test/reactivity/nodes/sync/flowConstant.test.ts +377 -0
- package/test/reactivity/nodes/sync/flowDerivation.test.ts +896 -0
- package/test/reactivity/nodes/sync/flowState.test.ts +341 -0
- package/test/reactivity/nodes/sync/flowWritableDerivation.test.ts +603 -0
- package/test/vitest.d.ts +10 -0
- package/tsconfig.json +31 -20
- package/typedoc.json +35 -35
- package/vite.config.ts +25 -23
- package/vitest.browser.config.ts +21 -0
- package/vitest.config.ts +12 -12
- package/.cursor/plans/unifier-flowresource-avec-flowderivation-c9506e24.plan.md +0 -372
- package/.cursor/plans/update-js-e795d61b.plan.md +0 -567
- package/dist/types/flow/base/flowDisposable.d.ts +0 -67
- package/dist/types/flow/base/flowDisposable.d.ts.map +0 -1
- package/dist/types/flow/base/flowEffect.d.ts +0 -127
- package/dist/types/flow/base/flowEffect.d.ts.map +0 -1
- package/dist/types/flow/base/flowGraph.d.ts +0 -97
- package/dist/types/flow/base/flowGraph.d.ts.map +0 -1
- package/dist/types/flow/base/flowSignal.d.ts +0 -134
- package/dist/types/flow/base/flowSignal.d.ts.map +0 -1
- package/dist/types/flow/base/flowTracker.d.ts +0 -15
- package/dist/types/flow/base/flowTracker.d.ts.map +0 -1
- package/dist/types/flow/base/index.d.ts +0 -7
- package/dist/types/flow/base/index.d.ts.map +0 -1
- package/dist/types/flow/base/utils.d.ts +0 -20
- package/dist/types/flow/base/utils.d.ts.map +0 -1
- package/dist/types/flow/collections/flowArray.d.ts +0 -148
- package/dist/types/flow/collections/flowArray.d.ts.map +0 -1
- package/dist/types/flow/collections/flowMap.d.ts +0 -224
- package/dist/types/flow/collections/flowMap.d.ts.map +0 -1
- package/dist/types/flow/collections/index.d.ts.map +0 -1
- package/dist/types/flow/index.d.ts +0 -4
- package/dist/types/flow/index.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/flowConstantAsync.d.ts +0 -137
- package/dist/types/flow/nodes/async/flowConstantAsync.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/flowDerivationAsync.d.ts +0 -137
- package/dist/types/flow/nodes/async/flowDerivationAsync.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/flowNodeAsync.d.ts +0 -343
- package/dist/types/flow/nodes/async/flowNodeAsync.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/flowReadonlyAsync.d.ts +0 -81
- package/dist/types/flow/nodes/async/flowReadonlyAsync.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/flowStateAsync.d.ts +0 -111
- package/dist/types/flow/nodes/async/flowStateAsync.d.ts.map +0 -1
- package/dist/types/flow/nodes/async/index.d.ts.map +0 -1
- package/dist/types/flow/nodes/index.d.ts +0 -3
- package/dist/types/flow/nodes/index.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/flowConstant.d.ts +0 -108
- package/dist/types/flow/nodes/sync/flowConstant.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/flowDerivation.d.ts +0 -100
- package/dist/types/flow/nodes/sync/flowDerivation.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/flowNode.d.ts +0 -314
- package/dist/types/flow/nodes/sync/flowNode.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/flowReadonly.d.ts +0 -57
- package/dist/types/flow/nodes/sync/flowReadonly.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/flowState.d.ts +0 -96
- package/dist/types/flow/nodes/sync/flowState.d.ts.map +0 -1
- package/dist/types/flow/nodes/sync/index.d.ts.map +0 -1
- package/dist/types/solid/converters.d.ts +0 -53
- package/dist/types/solid/converters.d.ts.map +0 -1
- package/dist/types/solid/index.d.ts +0 -3
- package/dist/types/solid/index.d.ts.map +0 -1
- package/dist/types/solid/primitives.d.ts +0 -181
- package/dist/types/solid/primitives.d.ts.map +0 -1
- package/docs/api/classes/FlowArray.md +0 -489
- package/docs/api/classes/FlowConstant.md +0 -350
- package/docs/api/classes/FlowDerivation.md +0 -334
- package/docs/api/classes/FlowEffect.md +0 -100
- package/docs/api/classes/FlowMap.md +0 -512
- package/docs/api/classes/FlowObservable.md +0 -306
- package/docs/api/classes/FlowResource.md +0 -380
- package/docs/api/classes/FlowResourceAsync.md +0 -362
- package/docs/api/classes/FlowSignal.md +0 -160
- package/docs/api/classes/FlowState.md +0 -368
- package/docs/api/classes/FlowStream.md +0 -367
- package/docs/api/classes/FlowStreamAsync.md +0 -364
- package/docs/api/classes/SolidDerivation.md +0 -75
- package/docs/api/classes/SolidResource.md +0 -91
- package/docs/api/classes/SolidState.md +0 -71
- package/docs/api/classes/TrackingContext.md +0 -33
- package/docs/api/functions/effect.md +0 -49
- package/docs/api/functions/resource.md +0 -52
- package/docs/api/functions/resourceAsync.md +0 -50
- package/docs/api/functions/stream.md +0 -53
- package/docs/api/functions/streamAsync.md +0 -50
- package/docs/api/interfaces/SolidObservable.md +0 -19
- package/docs/api/type-aliases/FlowStreamDisposer.md +0 -15
- package/docs/api/type-aliases/FlowStreamSetter.md +0 -27
- package/docs/api/type-aliases/FlowStreamUpdater.md +0 -32
- package/docs/api/type-aliases/SolidGetter.md +0 -17
- package/docs/guide/primitives/resources.md +0 -858
- package/docs/guide/primitives/streams.md +0 -931
- package/src/flow/base/flowDisposable.ts +0 -71
- package/src/flow/base/flowEffect.ts +0 -171
- package/src/flow/base/flowGraph.ts +0 -288
- package/src/flow/base/flowSignal.ts +0 -207
- package/src/flow/base/flowTracker.ts +0 -17
- package/src/flow/base/index.ts +0 -6
- package/src/flow/base/utils.ts +0 -19
- package/src/flow/collections/flowArray.ts +0 -409
- package/src/flow/collections/flowMap.ts +0 -398
- package/src/flow/nodes/async/flowConstantAsync.ts +0 -142
- package/src/flow/nodes/async/flowDerivationAsync.ts +0 -143
- package/src/flow/nodes/async/flowNodeAsync.ts +0 -474
- package/src/flow/nodes/async/flowReadonlyAsync.ts +0 -81
- package/src/flow/nodes/async/flowStateAsync.ts +0 -116
- package/src/flow/nodes/await/advanced/index.ts +0 -5
- package/src/flow/nodes/await/advanced/resource.ts +0 -134
- package/src/flow/nodes/await/advanced/resourceAsync.ts +0 -109
- package/src/flow/nodes/await/advanced/stream.ts +0 -188
- package/src/flow/nodes/await/advanced/streamAsync.ts +0 -176
- package/src/flow/nodes/await/flowConstantAwait.ts +0 -154
- package/src/flow/nodes/await/flowDerivationAwait.ts +0 -154
- package/src/flow/nodes/await/flowNodeAwait.ts +0 -508
- package/src/flow/nodes/await/flowReadonlyAwait.ts +0 -89
- package/src/flow/nodes/await/flowStateAwait.ts +0 -130
- package/src/flow/nodes/await/index.ts +0 -5
- package/src/flow/nodes/index.ts +0 -3
- package/src/flow/nodes/sync/flowConstant.ts +0 -111
- package/src/flow/nodes/sync/flowDerivation.ts +0 -105
- package/src/flow/nodes/sync/flowNode.ts +0 -439
- package/src/flow/nodes/sync/flowReadonly.ts +0 -57
- package/src/flow/nodes/sync/flowState.ts +0 -101
- package/src/solid/converters.ts +0 -139
- package/src/solid/index.ts +0 -2
- package/src/solid/primitives.ts +0 -215
- package/test/base/flowEffect.test.ts +0 -108
- package/test/base/flowGraph.test.ts +0 -485
- package/test/base/flowSignal.test.ts +0 -372
- package/test/collections/flowArray.asyncStates.test.ts +0 -1553
- package/test/collections/flowArray.scalars.test.ts +0 -1129
- package/test/collections/flowArray.states.test.ts +0 -1365
- package/test/collections/flowMap.asyncStates.test.ts +0 -1105
- package/test/collections/flowMap.scalars.test.ts +0 -877
- package/test/collections/flowMap.states.test.ts +0 -1097
- package/test/nodes/async/flowConstantAsync.test.ts +0 -860
- package/test/nodes/async/flowDerivationAsync.test.ts +0 -1517
- package/test/nodes/async/flowStateAsync.test.ts +0 -1387
- package/test/nodes/await/advanced/resource.test.ts +0 -129
- package/test/nodes/await/advanced/resourceAsync.test.ts +0 -108
- package/test/nodes/await/advanced/stream.test.ts +0 -198
- package/test/nodes/await/advanced/streamAsync.test.ts +0 -196
- package/test/nodes/await/flowConstantAwait.test.ts +0 -643
- package/test/nodes/await/flowDerivationAwait.test.ts +0 -1583
- package/test/nodes/await/flowStateAwait.test.ts +0 -999
- package/test/nodes/mixed/derivation.test.ts +0 -1527
- package/test/nodes/sync/flowConstant.test.ts +0 -620
- package/test/nodes/sync/flowDerivation.test.ts +0 -1373
- package/test/nodes/sync/flowState.test.ts +0 -945
- package/test/solid/converters.test.ts +0 -721
- package/test/solid/primitives.test.ts +0 -1031
- /package/dist/types/{flow → api/nodes}/collections/index.d.ts +0 -0
- /package/docs/guide/advanced/{upgrading.md → migration-v1.md} +0 -0
- /package/src/{flow → api/nodes}/collections/index.ts +0 -0
|
@@ -1,124 +1,76 @@
|
|
|
1
|
-
# Effects
|
|
1
|
+
# Side Effects & Subscribe
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Side effects are how you perform **actions** in response to reactive changes. They're the bridge between your reactive data and the outside world - updating the DOM, making API calls, saving to localStorage, and more.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Side effects are created by subscribing to reactive primitives using `subscribe()` or `.subscribe()`. When you subscribe, you get a `FlowEffect` object that can be disposed to stop the side effect.
|
|
6
6
|
|
|
7
7
|
### Key Characteristics
|
|
8
8
|
|
|
9
|
+
- **Two syntaxes**: `.subscribe()` for single primitive, `subscribe()` for multiple
|
|
9
10
|
- **Immediate execution**: Runs synchronously when created
|
|
10
11
|
- **Automatic re-execution**: Re-runs when dependencies change
|
|
11
12
|
- **Dynamic dependency tracking**: Dependencies adapt at runtime
|
|
12
|
-
- **
|
|
13
|
-
- **Disposal support**: Clean up resources when no longer needed
|
|
13
|
+
- **Returns FlowEffect**: Disposable handle to stop the subscription
|
|
14
14
|
|
|
15
|
-
## When to Use
|
|
15
|
+
## When to Use Subscribe
|
|
16
16
|
|
|
17
|
-
Use
|
|
17
|
+
Use subscribe when you need to:
|
|
18
18
|
|
|
19
19
|
- ✅ Perform side effects (DOM updates, API calls, localStorage)
|
|
20
20
|
- ✅ React to changes in reactive values
|
|
21
21
|
- ✅ Coordinate with external systems
|
|
22
|
-
- ✅ Set up subscriptions or event listeners
|
|
23
22
|
- ✅ Log or debug reactive changes
|
|
24
23
|
|
|
25
|
-
Don't use
|
|
24
|
+
Don't use subscribe when:
|
|
26
25
|
|
|
27
26
|
- ❌ Computing derived values (use derivations instead)
|
|
28
|
-
- ❌ The value needs to be used elsewhere reactively (use derivations)
|
|
29
27
|
- ❌ You only need to run code once (use regular functions)
|
|
30
28
|
|
|
31
|
-
## Creating Effects
|
|
29
|
+
## Creating Side Effects
|
|
32
30
|
|
|
33
|
-
|
|
31
|
+
There are two ways to create side effects, depending on your needs:
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
import { effect } from '@ersbeth/picoflow'
|
|
37
|
-
|
|
38
|
-
effect((t) => {
|
|
39
|
-
// Your side effect code here
|
|
40
|
-
// Use t to track dependencies
|
|
41
|
-
})
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
The parameter `t` is the **TrackingContext** - your tool for creating dependencies.
|
|
33
|
+
### Single Primitive - `.subscribe()`
|
|
45
34
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
Effects have several ways to interact with reactive values and manage their lifecycle.
|
|
49
|
-
|
|
50
|
-
### Tracking with `.get(t)` (Reactive)
|
|
51
|
-
|
|
52
|
-
Use `.get(t)` to create dependencies - the effect will re-run when the value changes:
|
|
35
|
+
When reacting to a single primitive, use the `.subscribe()` method:
|
|
53
36
|
|
|
54
37
|
```typescript
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
effect((t) => {
|
|
58
|
-
const name = $username.get(t) // Creates dependency
|
|
59
|
-
document.getElementById('username').textContent = name
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
$username.set('Bob') // Effect re-runs, DOM updates
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### Non-Reactive Reads with `.pick()`
|
|
66
|
-
|
|
67
|
-
Use `.pick()` to read the current value without creating a dependency:
|
|
38
|
+
import { state } from '@ersbeth/picoflow'
|
|
68
39
|
|
|
69
|
-
|
|
70
|
-
const $activeUserId = state(1)
|
|
71
|
-
const $userDatabase = state({ /* large object */ })
|
|
40
|
+
const $count = state(0)
|
|
72
41
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const user = database[activeId]
|
|
78
|
-
console.log('Active user:', user)
|
|
42
|
+
// Subscribe directly to the primitive
|
|
43
|
+
const effect = $count.subscribe((value) => {
|
|
44
|
+
console.log('Count is:', value)
|
|
79
45
|
})
|
|
80
46
|
|
|
81
|
-
//
|
|
82
|
-
|
|
47
|
+
// Later: dispose the effect
|
|
48
|
+
effect.dispose()
|
|
83
49
|
```
|
|
84
50
|
|
|
85
|
-
###
|
|
51
|
+
### Multiple Primitives - `subscribe()`
|
|
86
52
|
|
|
87
|
-
|
|
53
|
+
When combining multiple primitives, use the global `subscribe()` function:
|
|
88
54
|
|
|
89
55
|
```typescript
|
|
90
|
-
import {
|
|
56
|
+
import { state, subscribe } from '@ersbeth/picoflow'
|
|
91
57
|
|
|
92
|
-
const $refresh = signal()
|
|
93
|
-
|
|
94
|
-
effect((t) => {
|
|
95
|
-
$refresh.watch(t) // React to signal triggers
|
|
96
|
-
console.log('Refreshing data...')
|
|
97
|
-
fetchData()
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
$refresh.trigger() // Effect runs
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### Multiple Dependencies
|
|
104
|
-
|
|
105
|
-
Effects can track multiple reactive values:
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
58
|
const $firstName = state('Alice')
|
|
109
59
|
const $lastName = state('Smith')
|
|
110
60
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
$firstName.set('Bob') // Effect runs
|
|
119
|
-
$lastName.set('Jones') // Effect runs
|
|
61
|
+
// Combine multiple values
|
|
62
|
+
const effect = subscribe(
|
|
63
|
+
(t) => ({ first: $firstName.get(t), last: $lastName.get(t) }),
|
|
64
|
+
(data) => {
|
|
65
|
+
console.log('Full name:', data.first, data.last)
|
|
66
|
+
}
|
|
67
|
+
)
|
|
120
68
|
```
|
|
121
69
|
|
|
70
|
+
The parameter `t` is the **FlowTracker** - your tool for creating dependencies.
|
|
71
|
+
|
|
72
|
+
## Using Side-Effects
|
|
73
|
+
|
|
122
74
|
### Conditional Dependencies
|
|
123
75
|
|
|
124
76
|
Dependencies can be conditional - they're re-evaluated on each execution:
|
|
@@ -127,43 +79,51 @@ Dependencies can be conditional - they're re-evaluated on each execution:
|
|
|
127
79
|
const $showDetails = state(false)
|
|
128
80
|
const $details = state({ info: 'secret' })
|
|
129
81
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
82
|
+
subscribe(
|
|
83
|
+
(t) => {
|
|
84
|
+
const show = $showDetails.get(t)
|
|
85
|
+
if (show) {
|
|
86
|
+
return { show: true, details: $details.get(t) }
|
|
87
|
+
}
|
|
88
|
+
return { show: false, details: null }
|
|
89
|
+
},
|
|
90
|
+
(data) => {
|
|
91
|
+
if (data.show) {
|
|
92
|
+
console.log('Details:', data.details)
|
|
93
|
+
} else {
|
|
94
|
+
console.log('Details hidden')
|
|
95
|
+
}
|
|
136
96
|
}
|
|
137
|
-
|
|
97
|
+
)
|
|
138
98
|
|
|
139
|
-
// When $showDetails is false, changes to $details don't trigger the
|
|
140
|
-
$details.set({ info: 'new secret' }) //
|
|
99
|
+
// When $showDetails is false, changes to $details don't trigger the subscription
|
|
100
|
+
$details.set({ info: 'new secret' }) // Subscription doesn't run
|
|
141
101
|
|
|
142
102
|
// But once $showDetails is true...
|
|
143
|
-
$showDetails.set(true) //
|
|
144
|
-
$details.set({ info: 'updated' }) // Now this triggers the
|
|
103
|
+
$showDetails.set(true) // Subscription runs and now tracks $details
|
|
104
|
+
$details.set({ info: 'updated' }) // Now this triggers the subscription!
|
|
145
105
|
```
|
|
146
106
|
|
|
147
|
-
###
|
|
107
|
+
### Dispose
|
|
148
108
|
|
|
149
|
-
|
|
109
|
+
Subscriptions run indefinitely unless disposed. Always clean them up when no longer needed:
|
|
150
110
|
|
|
151
111
|
```typescript
|
|
152
112
|
const $count = state(0)
|
|
153
113
|
|
|
154
|
-
// Create
|
|
155
|
-
const
|
|
156
|
-
console.log(
|
|
114
|
+
// Create subscription
|
|
115
|
+
const effect = $count.subscribe((value) => {
|
|
116
|
+
console.log(value)
|
|
157
117
|
})
|
|
158
118
|
|
|
159
|
-
// Later... stop the
|
|
160
|
-
|
|
119
|
+
// Later... stop the subscription
|
|
120
|
+
effect.dispose()
|
|
161
121
|
|
|
162
|
-
// After disposal, the
|
|
122
|
+
// After disposal, the subscription won't run anymore
|
|
163
123
|
$count.set(10) // No console log
|
|
164
124
|
```
|
|
165
125
|
|
|
166
|
-
**Always dispose
|
|
126
|
+
**Always dispose subscriptions when:**
|
|
167
127
|
- Component unmounts (in UI frameworks)
|
|
168
128
|
- Feature is disabled
|
|
169
129
|
- User navigates away
|
|
@@ -176,25 +136,25 @@ $count.set(10) // No console log
|
|
|
176
136
|
function createUserPanel(userId: number) {
|
|
177
137
|
const $user = state(getUserData(userId))
|
|
178
138
|
|
|
179
|
-
|
|
180
|
-
updateUI(
|
|
139
|
+
$user.subscribe((user) => {
|
|
140
|
+
updateUI(user)
|
|
181
141
|
})
|
|
182
|
-
//
|
|
142
|
+
// Subscription never disposed! ⚠️
|
|
183
143
|
}
|
|
184
144
|
|
|
185
|
-
// Called 100 times = 100
|
|
145
|
+
// Called 100 times = 100 subscriptions still running!
|
|
186
146
|
|
|
187
147
|
// ✅ Proper cleanup
|
|
188
148
|
function createUserPanel(userId: number) {
|
|
189
149
|
const $user = state(getUserData(userId))
|
|
190
150
|
|
|
191
|
-
const
|
|
192
|
-
updateUI(
|
|
151
|
+
const effect = $user.subscribe((user) => {
|
|
152
|
+
updateUI(user)
|
|
193
153
|
})
|
|
194
154
|
|
|
195
155
|
return {
|
|
196
156
|
dispose: () => {
|
|
197
|
-
|
|
157
|
+
effect.dispose()
|
|
198
158
|
$user.dispose()
|
|
199
159
|
}
|
|
200
160
|
}
|
|
@@ -203,129 +163,140 @@ function createUserPanel(userId: number) {
|
|
|
203
163
|
|
|
204
164
|
## Lifecycle
|
|
205
165
|
|
|
206
|
-
|
|
166
|
+
Subscriptions execute immediately when created, track their dependencies, and re-execute when any dependency changes. Understanding this lifecycle is key to writing efficient reactive code.
|
|
207
167
|
|
|
208
|
-
When you create
|
|
168
|
+
When you create a subscription, it runs **synchronously** - not on the next tick, but right away. This allows subscriptions to establish initial dependencies and perform initial side effects. When a dependency changes, the subscription re-executes synchronously.
|
|
209
169
|
|
|
210
170
|
```mermaid
|
|
211
171
|
sequenceDiagram
|
|
212
172
|
participant User
|
|
213
173
|
participant $count as $count (State)
|
|
214
|
-
participant
|
|
174
|
+
participant Subscription
|
|
215
175
|
|
|
216
|
-
Note over User,
|
|
217
|
-
User->>
|
|
218
|
-
activate
|
|
219
|
-
Note over
|
|
176
|
+
Note over User,Subscription: 1. Creation Phase
|
|
177
|
+
User->>Subscription: "Create $count.subscribe(...)"
|
|
178
|
+
activate Subscription
|
|
179
|
+
Note over Subscription: Execute immediately
|
|
220
180
|
|
|
221
|
-
|
|
181
|
+
Subscription->>$count: Read value
|
|
222
182
|
activate $count
|
|
223
|
-
Note over $count: Register
|
|
224
|
-
$count-->>
|
|
183
|
+
Note over $count: Register Subscription as dependent
|
|
184
|
+
$count-->>Subscription: 0
|
|
225
185
|
deactivate $count
|
|
226
186
|
|
|
227
|
-
Note over
|
|
228
|
-
Note over
|
|
229
|
-
deactivate
|
|
187
|
+
Note over Subscription: "console.log(\"Count: 0\")"
|
|
188
|
+
Note over Subscription: Track: depends on $count
|
|
189
|
+
deactivate Subscription
|
|
230
190
|
|
|
231
|
-
Note over User,
|
|
191
|
+
Note over User,Subscription: 2. Change Phase
|
|
232
192
|
User->>$count: set(5)
|
|
233
193
|
activate $count
|
|
234
194
|
Note over $count: Value changed: 0 → 5
|
|
235
195
|
|
|
236
|
-
$count->>
|
|
196
|
+
$count->>Subscription: Notify & schedule
|
|
237
197
|
deactivate $count
|
|
238
198
|
|
|
239
|
-
activate
|
|
240
|
-
Note over
|
|
199
|
+
activate Subscription
|
|
200
|
+
Note over Subscription: Clear old dependencies<br/>Execute callback
|
|
241
201
|
|
|
242
|
-
|
|
202
|
+
Subscription->>$count: Read value
|
|
243
203
|
activate $count
|
|
244
|
-
Note over $count: Register
|
|
245
|
-
$count-->>
|
|
204
|
+
Note over $count: Register Subscription as dependent
|
|
205
|
+
$count-->>Subscription: 5
|
|
246
206
|
deactivate $count
|
|
247
207
|
|
|
248
|
-
Note over
|
|
249
|
-
Note over
|
|
250
|
-
deactivate
|
|
208
|
+
Note over Subscription: "console.log(\"Count: 5\")"
|
|
209
|
+
Note over Subscription: Track: depends on $count
|
|
210
|
+
deactivate Subscription
|
|
251
211
|
|
|
252
|
-
Note over User,
|
|
253
|
-
User->>
|
|
254
|
-
activate
|
|
255
|
-
Note over
|
|
256
|
-
Note over
|
|
257
|
-
deactivate
|
|
212
|
+
Note over User,Subscription: 3. Disposal Phase
|
|
213
|
+
User->>Subscription: dispose()
|
|
214
|
+
activate Subscription
|
|
215
|
+
Note over Subscription: Clear dependencies<br/>Unregister from $count
|
|
216
|
+
Note over Subscription: Mark as disposed
|
|
217
|
+
deactivate Subscription
|
|
258
218
|
|
|
259
219
|
User->>$count: set(10)
|
|
260
220
|
activate $count
|
|
261
221
|
Note over $count: Value changed<br/>No dependents to notify
|
|
262
222
|
deactivate $count
|
|
263
|
-
Note over
|
|
223
|
+
Note over Subscription: (Does not run - disposed)
|
|
264
224
|
```
|
|
265
225
|
|
|
266
226
|
### Key Lifecycle Points
|
|
267
227
|
|
|
268
|
-
1. **Creation & Immediate Execution**: The
|
|
269
|
-
2. **Dependency Registration**: Reactive reads
|
|
270
|
-
3. **Change Notification**: When dependencies change, the
|
|
271
|
-
4. **Re-execution**:
|
|
228
|
+
1. **Creation & Immediate Execution**: The subscription callback runs synchronously during creation
|
|
229
|
+
2. **Dependency Registration**: Reactive reads register the subscription as a dependent
|
|
230
|
+
3. **Change Notification**: When dependencies change, the subscription is scheduled to re-run
|
|
231
|
+
4. **Re-execution**: Subscription clears old dependencies, runs again, re-registers new dependencies
|
|
272
232
|
5. **Disposal**: Clears all dependencies, unregisters from all reactive values, prevents future execution
|
|
273
233
|
|
|
274
234
|
This immediate, synchronous execution model means:
|
|
275
|
-
- **
|
|
235
|
+
- **Subscriptions establish dependencies on first run** (no waiting)
|
|
276
236
|
- **Changes trigger re-execution immediately** (synchronous)
|
|
277
237
|
- **Dynamic dependencies adapt automatically** (conditional tracking)
|
|
278
238
|
|
|
279
239
|
## Best Practices
|
|
280
240
|
|
|
281
|
-
### Keep
|
|
241
|
+
### Keep Subscriptions Focused
|
|
282
242
|
|
|
283
|
-
Each
|
|
243
|
+
Each subscription should do one thing:
|
|
284
244
|
|
|
285
245
|
```typescript
|
|
286
246
|
// ❌ Doing too much
|
|
287
|
-
|
|
288
|
-
updateDOM(
|
|
289
|
-
saveToStorage(
|
|
290
|
-
sendAnalytics(
|
|
291
|
-
updateTitle(
|
|
247
|
+
$count.subscribe((value) => {
|
|
248
|
+
updateDOM(value)
|
|
249
|
+
saveToStorage(value)
|
|
250
|
+
sendAnalytics(value)
|
|
251
|
+
updateTitle(value)
|
|
292
252
|
})
|
|
293
253
|
|
|
294
254
|
// ✅ Separate concerns
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
255
|
+
$count.subscribe((value) => updateDOM(value))
|
|
256
|
+
$count.subscribe((value) => saveToStorage(value))
|
|
257
|
+
$count.subscribe((value) => sendAnalytics(value))
|
|
258
|
+
$count.subscribe((value) => updateTitle(value))
|
|
299
259
|
```
|
|
300
260
|
|
|
301
|
-
**Why?** Easier to debug, test, and disable individual
|
|
261
|
+
**Why?** Easier to debug, test, and disable individual subscriptions.
|
|
302
262
|
|
|
303
|
-
### Avoid Creating
|
|
263
|
+
### Avoid Creating Subscriptions Inside Subscriptions
|
|
304
264
|
|
|
305
265
|
```typescript
|
|
306
|
-
// ❌ Bad - creates new
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
console.log('Nested:', count) // Memory leak!
|
|
266
|
+
// ❌ Bad - creates new subscriptions on every run
|
|
267
|
+
$count.subscribe((count) => {
|
|
268
|
+
$other.subscribe((other) => {
|
|
269
|
+
console.log('Nested:', count, other) // Memory leak!
|
|
311
270
|
})
|
|
312
271
|
})
|
|
313
272
|
|
|
314
|
-
// ✅ Good - create
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
273
|
+
// ✅ Good - create subscriptions at the top level
|
|
274
|
+
subscribe(
|
|
275
|
+
(t) => ({ count: $count.get(t), other: $other.get(t) }),
|
|
276
|
+
(data) => {
|
|
277
|
+
console.log('Values:', data.count, data.other)
|
|
278
|
+
}
|
|
279
|
+
)
|
|
319
280
|
```
|
|
320
281
|
|
|
321
282
|
### Handle Errors
|
|
322
283
|
|
|
323
|
-
|
|
284
|
+
Use the `onError` callback or wrap risky operations in try-catch:
|
|
324
285
|
|
|
325
286
|
```typescript
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
287
|
+
// ✅ Using onError callback
|
|
288
|
+
subscribe(
|
|
289
|
+
(t) => $data.get(t),
|
|
290
|
+
(data) => {
|
|
291
|
+
updateDOM(data)
|
|
292
|
+
},
|
|
293
|
+
(error) => {
|
|
294
|
+
console.error('Failed to update DOM:', error)
|
|
295
|
+
}
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
// ✅ Or use try-catch
|
|
299
|
+
$data.subscribe((data) => {
|
|
329
300
|
try {
|
|
330
301
|
updateDOM(data)
|
|
331
302
|
} catch (error) {
|
|
@@ -336,20 +307,18 @@ effect((t) => {
|
|
|
336
307
|
|
|
337
308
|
### Be Careful with Infinite Loops
|
|
338
309
|
|
|
339
|
-
Don't update dependencies inside the same
|
|
310
|
+
Don't update dependencies inside the same subscription:
|
|
340
311
|
|
|
341
312
|
```typescript
|
|
342
313
|
const $count = state(0)
|
|
343
314
|
|
|
344
315
|
// ❌ Infinite loop!
|
|
345
|
-
|
|
346
|
-
const count = $count.get(t)
|
|
316
|
+
$count.subscribe((count) => {
|
|
347
317
|
$count.set(count + 1) // Triggers itself!
|
|
348
318
|
})
|
|
349
319
|
|
|
350
320
|
// ✅ Use a different state
|
|
351
|
-
|
|
352
|
-
const count = $count.get(t)
|
|
321
|
+
$count.subscribe((count) => {
|
|
353
322
|
$doubled.set(count * 2) // Updates different state
|
|
354
323
|
})
|
|
355
324
|
```
|
|
@@ -361,8 +330,7 @@ When you don't need a value, just an event:
|
|
|
361
330
|
```typescript
|
|
362
331
|
const $refresh = signal()
|
|
363
332
|
|
|
364
|
-
|
|
365
|
-
$refresh.watch(t) // Track signal without reading a value
|
|
333
|
+
$refresh.subscribe(() => {
|
|
366
334
|
fetchData()
|
|
367
335
|
})
|
|
368
336
|
|
|
@@ -372,87 +340,33 @@ $refresh.trigger()
|
|
|
372
340
|
|
|
373
341
|
## Common Pitfalls
|
|
374
342
|
|
|
375
|
-
###
|
|
376
|
-
|
|
377
|
-
**Problem**: Using `.pick()` instead of `.get(t)` breaks reactivity.
|
|
378
|
-
|
|
379
|
-
```typescript
|
|
380
|
-
// ❌ No dependency created - effect runs only once
|
|
381
|
-
effect((t) => {
|
|
382
|
-
console.log($count.pick()) // Using .pick() instead of .get(t)
|
|
383
|
-
})
|
|
343
|
+
### Not Disposing Subscriptions
|
|
384
344
|
|
|
385
|
-
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
**Solution**: Always use `.get(t)` to create dependencies:
|
|
389
|
-
|
|
390
|
-
```typescript
|
|
391
|
-
// ✅ Correct
|
|
392
|
-
effect((t) => {
|
|
393
|
-
console.log($count.get(t))
|
|
394
|
-
})
|
|
395
|
-
|
|
396
|
-
$count.set(10) // Effect runs
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
### Not Disposing Effects
|
|
400
|
-
|
|
401
|
-
**Problem**: Effects continue running even when no longer needed.
|
|
345
|
+
**Problem**: Subscriptions continue running even when no longer needed.
|
|
402
346
|
|
|
403
347
|
```typescript
|
|
404
348
|
// ❌ Memory leak in component lifecycle
|
|
405
349
|
function MyComponent() {
|
|
406
|
-
|
|
407
|
-
updateView(
|
|
350
|
+
$data.subscribe((data) => {
|
|
351
|
+
updateView(data)
|
|
408
352
|
})
|
|
409
353
|
// Never disposed!
|
|
410
354
|
}
|
|
411
355
|
|
|
412
|
-
// Each component creation adds another
|
|
356
|
+
// Each component creation adds another subscription that never stops
|
|
413
357
|
```
|
|
414
358
|
|
|
415
|
-
**Solution**: Always dispose
|
|
359
|
+
**Solution**: Always dispose subscriptions when done:
|
|
416
360
|
|
|
417
361
|
```typescript
|
|
418
362
|
// ✅ Proper cleanup
|
|
419
363
|
function MyComponent() {
|
|
420
|
-
const
|
|
421
|
-
updateView(
|
|
364
|
+
const effect = $data.subscribe((data) => {
|
|
365
|
+
updateView(data)
|
|
422
366
|
})
|
|
423
367
|
|
|
424
368
|
return {
|
|
425
|
-
cleanup: () =>
|
|
369
|
+
cleanup: () => effect.dispose()
|
|
426
370
|
}
|
|
427
371
|
}
|
|
428
|
-
```
|
|
429
|
-
|
|
430
|
-
### Async Operations Without Care
|
|
431
|
-
|
|
432
|
-
**Problem**: Race conditions when using async operations in effects.
|
|
433
|
-
|
|
434
|
-
```typescript
|
|
435
|
-
// ⚠️ Race condition possible
|
|
436
|
-
effect(async (t) => {
|
|
437
|
-
const id = $userId.get(t)
|
|
438
|
-
const data = await fetchUser(id) // If $userId changes during fetch...
|
|
439
|
-
displayUser(data) // ...we might display wrong user!
|
|
440
|
-
})
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
**Solution**: Check if values are still relevant after async operations:
|
|
444
|
-
|
|
445
|
-
```typescript
|
|
446
|
-
// ✅ Better - check if still relevant
|
|
447
|
-
effect(async (t) => {
|
|
448
|
-
const id = $userId.get(t)
|
|
449
|
-
const data = await fetchUser(id)
|
|
450
|
-
|
|
451
|
-
// Verify ID didn't change during fetch
|
|
452
|
-
if ($userId.pick() === id) {
|
|
453
|
-
displayUser(data)
|
|
454
|
-
}
|
|
455
|
-
})
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
**Why this matters**: Between starting an async operation and its completion, your reactive values might change. Always verify the context is still valid before applying results.
|
|
372
|
+
```
|