State objects are an event-oriented way of managing application state and reacting to changes.
It makes use of built-in features such as Proxy
and EventTarget
to save code and give users less to remember.
By default, state changes are only queued up and processed in a microtask, allowing for batch-processing.
This means that for repeated changes to the same property, the user can decide to process all the changes in one go or even discard everything but the last value of each property.
That way one can easily avoid some types of unnecessary redraws, network requests, etc.
To make code more readable, the constructor defaults to adding an event listener that checks for a method called [prop]Changed
in the state object, and calls it with the new value. This behaviour can be disabled by setting the methods
option to false.
The state object also has a getter and setter pair for the `state` attribute, which simply accesses this same attribute on the proxy object. This is simply a convenience feature to save some typing on single-variable states.
defer
methods
A simple counter state that prints a new count to the console every time it gets updated.
This example uses an event listener instead to get notified of all property changes. Collecting changes into a map is an easy way of de-duplicating their values and keeping only the last one.
The StorageState
subclass of State
implements the same API but is backed by a
Storage
object.
By default, StorageState
uses the
window.localStorage
object, but you can change this by
passing the storage
option in the constructor.
When using the value
short-hand to have a different
StorageState
for every individual value, these would
all override the same key in the storage. To remedy this, the
key
option can be used to redirect reads and writes
of the "value"
key to a different key in the storage.
Using a storage object comes with the disadvantage that all values must be stored in a serialised form, which won't work for all data and will break identity. Specifically, all values are converted to JSON strings for storage.
When a fallback option is needed, for example to support clients without
localStorage
without breaking the page, the
MapStorage
object implements the Storage
API
and is backed by a plain JavaScript Map
object.