Middlewares
Middlewares are implicit methods to deal with side effects of your superstates.
Let's say we want to display an alert
whenever a superstate
changes. One simple way to achieve it would be through
a simple Middleware:
function myMiddleware({ eventType }) {
if (eventType === 'after:change') {
alert('hello world!')
return
}
}
const count = superstate(0).use([myMiddleware])
count.set(10) // here your `alert()` would be called
And honestly, Middlewares are that simple!
Event Types
One of the most important aspects of a Middleware is the eventType
property superstate
passes to it. The eventType
helps you decide what to do and when.
Here's a list of all the available event types:
init
before:set
after:set
before:sketch
after:sketch
before:publish
after:publish
before:change
after:change
before:discard
after:discard
before:broadcast:now
after:broadcast:now
before:broadcast:draft
after:broadcast:draft
The init
event type
The init
event type is executed once when a Middleware is successfully attached to a superstate:
function initMiddleware({ eventType }) {
if (eventType === 'init') {
alert('initMiddleware was installed successfully!')
return
}
}
const count = superstate(0).use([initMiddleware]) // the `alert()` would be called here.
May be important to note that init
won't ever be called again despite this very first time.
before:change
and after:change
Just like init
, these change
events are special, because it has two different instigators.
It'll be triggered when...
- you
.publish()
successfully and/or, - you
.set()
successfully.
info
Note that the change
event will not trigger for changes made to the draft. If you are interested on draft events,
please use before:sketch
and after:sketch
.
Before/After events
As you may have noticed, some events are prefixed with before:
or after:
.
These events will only trigger when an action was successfully achieved, and only before/after the action itself.
To illustrate an example, before:publish
occurs when you call .publish()
, but before the publish method has published
your changes; at the same time, after:publish
also occurs when you call .publish()
, except it will be executed after
the publish method has published your changes. Both before:publish
and after:publish
will only occur if publishing was successful.
Advanced Middlewares
eventType
is not the only property exposed to Middlewares. Actually, Middlewares have access to the exact same functions
a superstate
object has, such as publish
, set
, discard
, etc (Learn more). To illustrate you an example:
function myMiddleware({ eventType, set, now }) {
if (eventType === 'after:publish') {
sketch(now())
}
}
const count = superstate(0).use([myMiddleware])
count.publish(5)
The Middleware above will assign your draft with the value of now()
, which is 5
, every time you .publish()
something.
Infinite loop!
If you call publish()
inside a Middleware that does something after you publish()
, expect an infinite loop. That said, don't do that!
When Middlewares make sense
From Wikipedia:
Middleware is a type of computer software that provides services to software applications beyond those available from the operating system. It can be described as "software glue".
Middleware makes it easier for software developers to implement communication and input/output, so they can focus on the specific purpose of their application.
To name you a practical example of where a Middleware can be useful, the localStorage adapter is a Middleware. Instead of having to manually write/read to/from localStorage, a Middleware was written to do that for us.
If you need to automate something in your superstates, Middlewares can be the answer.
TypeScript
function myMiddleware<T = number>(input: IMiddlewareInput<T>): void {
// ... your function
}
const count = superstate(0).use([myMiddleware])
Feel free to change T = number
to whatever you need.