StatefulEvt<T>
A
StatefulEvt
is an Evt stat keep a reference to the last value posted.You can think of it as way to observe when a value is changed.
When you attach to a
StatefulEvt the callback is immediately called with the current value (except with
attachExtract and
attachOnceExtract).
Property type:
T
reading the property gives the last event data posted. Setting the property (
evt.state = data
) is equivalent to calling .post(data)
.import { Evt } from "evt";
const evtCount = Evt.create(0); // Equivalent wit new StatefulEvt<number>(0)
evtCount.attach(console.log);
console.log(evtCount.state); //Pints "state: 0"
evtIsConnected.post(1); //Pints "1"
console.log(evtCount.state); //Prints "1";
evtCount.state++; //Prints "2"
console.log(evtCount.state); //Pints "2";
Same as
evt.pipe(...)
but return a StatefulEvt
. Be aware that the current state of the StatefulEvt
must be matched by the operator ( if any ) when invoking .pipe()
, elst an exception will be thrown.import { Evt } from "evt";
type Circle = {
color: "WHITE" | "RED";
radius: number;
};
const evtSelectedCircle = Evt.create<Circle>({ "color": "RED", "radius": 3 });
const evtSelectedCricleColor =
evtSelectedCircle.pipe(circle=> [ cicle.color ]);
evtSelectedCircleColor.attach(console.log);
Basic example:
import { Evt } from "evt";
const evtSrc = Evt.create<string>();
const evtFoo = evtSrc.toStatefull("initial value");
console.log(evtFoo.state === "initial value");
evtStr.post("new value");
console.log(evtFoo.state === "new value");
Concrete example:
import { Evt } from "evt";
// Evt that post whenever the window is resized window.addEventListener("resize", ...)
const evtResize = Evt.from(window, "resize");
// A statefulle evt with evtInnerWith state which is always the current value of
// window.innerSize.
const evtInnerWidth = evtResize
.toStatefull() // convert into a statefull evt with initial value set to unefined
.pipe(()=> [window.innerWidth]);
When using stetefull Evt is often usefull to have event posted only when the state value has changed. For that purpose you can pipe with the onlyIfChanged operator.
Concrete example:
If we take the previous example:
import { Evt } from "evt";
const evtInnerWidth = Evt.from(window, "resize")
.toStatefull()
.pipe(()=> [window.innerWidth]);
evtInnerWith.attach(innerWidth => {
// This callback will be called whenever the screen is resized
// including if only if the height has changed because
// window.addEventListener("resize", ()=> ...
// is the source event emitter.
});
Now if we put the
onlyIfChanged
operator intor the mix: import { Evt, onlyIfChanged } from "evt";
const evtInnerWidth = Evt.from(window, "resize")
.toStatefull()
.pipe(()=> [window.innerWidth])
.pipe(onlyIfChanged());
evtInnerWith.attach(innerWidth => {
// This callback will only be called whenever window.innerWidth
// actually changes.
});
import { Evt } from "evt";
const evtIsBlue= Evt.create(false);
const evtIsBig= Evt.create(false);
const evtIsBigAndBlue = Evt.merge([
evtIsBlue.evtChange,
evtIsBig.evtChange
])
.toStateful()
.pipe(()=> [ evtIsBlue.state && evtIsBig.state ])
;
console.log(evtIsBigAndBlue.state); // Prints "false"
evtIsBlue.state= true;
console.log(evtIsBigAndBlue.state); // Prints "false"
evtIsBig.state= true;
console.log(evtIsBigAndBlue.state); // Prints "true"
To prevent a StatefulEvt to be posted by parts of the code that is not supposed to StatefulEvt can be exposed as
StatefulReadonlyEvt
.import { StatefulEvt, StatefulReadonlyEvt } from "evt";
//Return an event that post every second.
function generateEvtTick(delay: number): StatefulReadonlyEvt<number> {
const evtTick= new StatefulEvt(0);
setInterval(()=> evtTick.state++, delay);
retrun evtTick;
}
const evtTick= generateTick(1000);
evtTick.state++; // TS ERROR
evtTick.post(2); // TS ERROR
Return a stateless copy of the
Evt.
import { Evt } from "evt";
const evtText= Evt.create("foo");
//x is Evt<string>
const x= evtText.toStateless();
evt.toStateless()
is equivalent to Evt.prototype.pipe.call(evt)
Last modified 20d ago