Using observables to manage reactivity
How a program responds to variable data or user interactions is one of the fundamental problems of programming. If we desire to solve the issue in a declarative manner, observables may be a viable approach.
// when NPM
import { O } from "deka-dom-el/observables";
// https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js
/**
* @type {ddeObservable}
* */
/**
* @type {ddeActions}
* */
# Introducing observables
Using observables, we split program logic into the three parts. Firstly (α), we create a variable (constant) representing reactive value. Somewhere later, we can register (β) a logic reacting to the observable value changes. Similarly, in a remaining part (γ), we can update the observable value.
import { O } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
// α — `observable` represents a reactive value
const observable= O(0);
// β — just reacts on observable changes
O.on(observable, console.log);
// γ — just updates the value
observable(observable()+1);
setInterval(()=> observable(observable()+1), 5000);
All this is just an example of Event-driven programming and Publish–subscribe pattern (compare for example with fpubsub library). All three parts can be in some manner independent and still connected to the same reactive entity.
Observables are implemented in the library as functions. To see current value of observable, just call it without any arguments console.log(observable())
. To update the observable value, pass any argument observable('a new value')
. For listenning the observable value changes, use O.on(observable, console.log)
.
Similarly to the on
function to register DOM events listener. You can use AbortController
/AbortSignal
to off/stop listenning. For representing “live” piece of code computation pattern:
import { O } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
const observable= O(0);
// computation pattern
const double= O(()=> 2*observable());
const ac= new AbortController();
O.on(observable, v=> console.log("observable", v), { signal: ac.signal });
O.on(double, v=> console.log("double", v), { signal: ac.signal });
observable(observable()+1);
const interval= 5000;
const id= setInterval(()=> observable(observable()+1), interval);
ac.signal.addEventListener("abort",
()=> setTimeout(()=> clearInterval(id), 2*interval));
setTimeout(()=> ac.abort(), 3*interval)
# Mnemonic
O(<value>)
— observable: reactive valueO(()=> <computation>)
— observable: reactive value dependent on calculation using other observablesO.on(<observable>, <listener>[, <options>])
— listen to the observable value changesO.clear(...<observables>)
— off and clear observablesO(<value>, <actions>)
— observable: pattern to create complex reactive objects/arraysO.action(<observable>, <action-name>, ...<action-arguments>)
— invoke an action for given observable