badmfck-signal
Version:
An implementation of a signaling mechanism used to connect components and transfer data between them
139 lines (138 loc) • 4.64 kB
JavaScript
;
// T - request,
// K - response
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Binder = void 0;
const _1 = __importStar(require("."));
/**
*
* Binder provide functionality to bind data to any component
* T - request type
* K - data type
*
* To use Binder you need to create instance of it and provide request and response types
* Use request() to send request to data source via request pipeline, anyone can subscribe to request pipeline
* Use subscribe() to request data from source via response pipeline, anyone can subscribe to response pipeline
* Use execute() to request data from source and wait for response
* Use use() to bind data to react component, before using it you need to setup react hooks, by calling Binder.setupReact(useState,useEffect)
*
*/
class Binder {
static reactUseState = null;
static reactUseEffect = null;
static nextID = 0;
name;
type = "binder";
readyListener = new _1.default(); // OUT ->
requestListener = new _1.default(); // IN <-
constructor(name) {
if (!name)
name = "Binder_" + (Binder.nextID++);
this.name = name;
}
/**
* Setup react hook before using it
* @param useState - reference to react useState
* @param useEffect - reference to react useEffect
*/
static setupReact(useState, useEffect) {
if (Binder.reactUseEffect && Binder.reactUseState)
return;
Binder.reactUseEffect = useEffect;
Binder.reactUseState = useState;
_1.default.setupReact(useState, useEffect);
}
/**
subscribe to request pipeline
*/
onRequest(cb) {
this.requestListener.subscribe(cb);
}
/**
subscribe to response pipeline
*/
subscribe(cb) {
this.readyListener.subscribe(cb);
}
/**
invoke response pipeline
*/
invoke(data) {
this.readyListener.invoke(data);
}
/*
invoke request pipeline
*/
request(req) {
this.requestListener.invoke(req);
}
/**
Execute binder & wait for results
*/
async execute(req) {
const cb = { resolve: null };
const promise = new Promise((resolve, reject) => { cb.resolve = resolve; });
const sh = new _1.SignalHandler();
sh.add(this.readyListener, data => {
if (cb.resolve)
cb.resolve(data);
sh.clear();
});
this.requestListener.invoke(req ?? null);
return promise;
}
/**
* Binder hook
* request - request object for data loading procedure
* initial - initial data object
* dependency - react dependency array
* return - array [data,busy], where first element - Binded data, second element - Busy indicator
*/
use(request, initial, dependency) {
const [data, setData] = Binder.reactUseState(initial ?? null);
const [busy, setBusy] = Binder.reactUseState(false);
Binder.reactUseEffect(() => {
const sh = new _1.SignalHandler();
sh.add(this.readyListener, data => {
setData(data);
setBusy(false);
});
sh.add(this.requestListener, req => {
setBusy(true);
});
this.requestListener.invoke(request ?? null);
return () => {
sh.clear();
};
}, dependency ?? []);
return [data, busy];
}
clear() {
this.requestListener.removeAll();
this.readyListener.removeAll();
}
}
exports.Binder = Binder;