@prodo/core
Version:
Core package for [Prodo](https://prodo.dev). See [documentation](https://docs.prodo.dev) for more info.
139 lines (117 loc) • 3.17 kB
text/typescript
import { unstable_batchedUpdates } from "react-dom";
import logger from "./logger";
import { Event, Node, Store, WatchTree } from "./types";
import { splitPath } from "./utils";
export const subscribe = (
store: Store<any, any>,
path: string[],
node: Node,
) => {
// root tree
let tree: WatchTree = store.watchTree;
tree.subs.add(node);
// watching the entire state
if (path.length === 0) {
tree.esubs.add(node);
return;
}
// add node to subs of all child trees
path.forEach(key => {
if (!tree.children[key]) {
tree.children[key] = {
subs: new Set(),
esubs: new Set(),
children: {},
};
}
tree = tree.children[key];
tree.subs.add(node);
});
// add node to esubs of exact part of state tree that was subscribed
tree.esubs.add(node);
};
export const unsubscribe = (
store: Store<any, any>,
path: string[],
node: Node,
) => {
let tree: WatchTree = store.watchTree;
tree.subs.delete(node);
if (path.length === 0) {
tree.esubs.delete(node);
return;
}
for (const pathKey of path) {
const prev = tree;
tree = tree.children[pathKey];
if (node.unsubscribe) {
node.unsubscribe({
name: node.name,
compId: node.compId,
});
}
tree.subs.delete(node);
// there are no more subscribers to children of this tree
// cut the branch
if (tree.subs.size === 0) {
delete prev.children[pathKey];
break;
}
}
tree.esubs.delete(node);
};
export const get = (universe: any, pathKey: string): any =>
splitPath(pathKey).reduce((x: any, y: any) => x && x[y], universe);
export const submitPatches = (
store: Store<any, any>,
universe: any,
event: Event,
) => {
const callbacksSet = new Set<Node>();
const { patches } = event;
patches.forEach(({ path }) => {
let subtree = store.watchTree;
// tslint:disable-next-line:prefer-for-of
for (let i = 0; i < path.length; i += 1) {
const key = path[i];
if (!subtree.children[key]) {
break;
}
subtree = subtree.children[key];
Array.from(i === path.length - 1 ? subtree.subs : subtree.esubs).forEach(
x => callbacksSet.add(x),
);
}
});
const comps: { [key: string]: any } = {};
const compIds: number[] = [];
Array.from(callbacksSet)
.sort((x: Node, y: Node) => x.compId - y.compId)
.forEach((x: Node) => {
if (!comps[x.compId]) {
compIds.push(x.compId);
comps[x.compId] = {
setState: x.setState,
status: x.status,
name: x.name,
newValues: {},
};
}
comps[x.compId.toString()].newValues[x.pathKey] = get(
universe,
x.pathKey,
);
});
logger.info("[update cycle]", comps);
event.rerender = {};
unstable_batchedUpdates(() =>
Object.keys(comps).forEach(compId => {
const { setState, name, newValues, status } = comps[compId];
if (!status.unmounted) {
event.rerender![comps[compId].name] = true;
logger.info(`[upcoming state update] ${name}`, newValues, status);
setState(newValues);
}
}),
);
};