Lifecycle
A state flow should live as long as the feature using it. Stative cleans up the children managed by a closure, and external resources can share that lifecycle.
Clean up what you create
The caller is responsible for destroying a root closure created with render. Children created and managed through nested descriptors, useCreate, useMap, and similar helpers are cleaned up with it.
Unsubscribing and destroying a closure serve different purposes. unsubscribe() stops notifications for that subscription; destroy() ends the closure's lifetime and releases its internal dependencies.
An external state passed as an input, such as text, is not destroyed with the root closure. It may be shared with other features, so the code that created it should decide when to clean it up.
Manage timers and event sources
ReactiveState can turn external events into a state with a current value. Supply initial, publish updates from emitter, and return a cleanup function:
useClearable registers the state as a resource owned by the closure. Destroying clock destroys the state, which runs the emitter's cleanup and stops the timer.
By default, emitter starts when the state is first accessed or subscribed to. Canceling one subscription does not destroy that state; call destroy() on its owning closure when it is no longer needed.
Use the same pattern for event listeners and other sources: establish the connection, call observer.next(value) for updates, and return a function that disconnects it.
Register other cleanup work
Inside once, you can also pass a cleanup function directly to useClearable:
The function runs when the closure is destroyed. useClearable also accepts cancellable subscriptions and objects with a destroy() method. In a class, use this.clearable(...).
Completion and errors
An external source can call observer.complete() to finish or observer.error(error) to report a failure. A subscription can handle each case:
MutableState provides matching complete() and error() methods. A completed or failed state no longer accepts updates. If the feature supports retries, it is often more useful to represent loading results and errors as ordinary state values, then let the application decide what happens next.