TeaWeb/shared/js/ui/react-elements/ReactComponentBase.ts

152 lines
4.7 KiB
TypeScript
Raw Normal View History

2020-04-06 14:28:15 +00:00
import * as React from "react";
import * as ReactDOM from "react-dom";
export enum BatchUpdateType {
UNSET = -1,
GENERAL = 0,
CHANNEL_TREE = 1
}
interface UpdateBatch {
enabled: boolean;
enable_count: number;
update: {
c: any;
s: any;
b: () => void;
}[];
force: {
c: any;
b: () => void;
}[];
}
const generate_batch = () => { return { enabled: false, enable_count: 0, update: [], force: [] }};
let update_batches: {[key: number]:UpdateBatch} = {
0: generate_batch(),
1: generate_batch()
};
2020-04-21 14:17:21 +00:00
(window as any).update_batches = update_batches;
export function BatchUpdateAssignment(type: BatchUpdateType) {
return function (constructor: Function) {
if(!ReactComponentBase.prototype.isPrototypeOf(constructor.prototype))
throw "Class/object isn't an instance of ReactComponentBase";
const didMount = constructor.prototype.componentDidMount;
constructor.prototype.componentDidMount = function() {
if(typeof this.update_batch === "undefined")
this.update_batch = update_batches[type];
if(typeof didMount === "function")
didMount.call(this, arguments);
};
}
}
2020-04-06 14:28:15 +00:00
export abstract class ReactComponentBase<Properties, State> extends React.Component<Properties, State> {
private update_batch: UpdateBatch;
private batch_component_id: number;
private batch_component_force_id: number;
2020-04-06 14:28:15 +00:00
constructor(props: Properties) {
super(props);
this.batch_component_id = -1;
this.batch_component_force_id = -1;
2020-04-06 14:28:15 +00:00
this.state = this.defaultState();
2020-04-06 14:28:15 +00:00
this.initialize();
}
protected initialize() { }
protected defaultState() : State { return {} as State; }
2020-04-06 14:28:15 +00:00
setState<K extends keyof State>(
state: ((prevState: Readonly<State>, props: Readonly<Properties>) => (Pick<State, K> | State | null)) | (Pick<State, K> | State | null),
callback?: () => void
): void {
if(typeof this.update_batch !== "undefined" && this.update_batch.enabled) {
const obj = {
c: this,
s: Object.assign(this.update_batch.update[this.batch_component_id]?.s || {}, state),
b: callback
};
if(this.batch_component_id === -1)
this.batch_component_id = this.update_batch.update.push(obj) - 1;
else
this.update_batch.update[this.batch_component_id] = obj;
} else {
super.setState(state, callback);
}
}
forceUpdate(callback?: () => void): void {
if(typeof this.update_batch !== "undefined" && this.update_batch.enabled) {
const obj = {
c: this,
b: callback
};
if(this.batch_component_force_id === -1)
this.batch_component_force_id = this.update_batch.force.push(obj) - 1;
else
this.update_batch.force[this.batch_component_force_id] = obj;
} else {
super.forceUpdate(callback);
2020-04-10 18:57:50 +00:00
}
2020-04-06 14:28:15 +00:00
}
protected classList(...classes: (string | undefined)[]) {
return [...classes].filter(e => typeof e === "string" && e.length > 0).join(" ");
}
protected hasChildren() {
const type = typeof this.props.children;
if(type === "undefined") return false;
return Array.isArray(this.props.children) ? this.props.children.length > 0 : true;
}
}
export function batch_updates(type: BatchUpdateType) {
const batch = update_batches[type];
if(typeof batch === "undefined") throw "unknown batch type";
batch.enabled = true;
batch.enable_count++;
}
export function flush_batched_updates(type: BatchUpdateType, force?: boolean) {
const batch = update_batches[type];
if(typeof batch === "undefined") throw "unknown batch type";
if(--batch.enable_count > 0 && !force) return;
if(batch.enable_count < 0) throw "flush_batched_updates called more than batch_updates!";
const updates = batch.update;
const forces = batch.force;
batch.update = [];
batch.force = [];
batch.enabled = batch.enable_count > 0;
ReactDOM.unstable_batchedUpdates(() => {
{
let index = updates.length;
while(index--) { /* fastest way to iterate */
const update = updates[index];
update.c.batch_component_id = -1;
update.c.setState(update.s, update.b);
}
}
{
let index = forces.length;
while(index--) { /* fastest way to iterate */
const update = forces[index];
update.c.batch_component_force_id = -1;
update.c.forceUpdate(update.b);
}
}
});
2020-04-06 14:28:15 +00:00
}