Root
At the top level you create a reactive program. Call the Reactive.Root function with your
reactive program callback.
const root = Reactive.Root(() => {
// your reactive program will go here
});
Root Object
The architecture is a dependency graph of nodes. A running program is data, and that data is grouped by scope. A scope is a block of nodes built together. The root holds the root scope the program builds, the first one created.
{
rootScope: undefined, // the root scope, a block of nodes, once the program has run
};
The root does not hold nodes loose. Each node is an entry inside a scope, and every other scope is reached from the root scope through the graph. Later pages add more fields to the root as they need them: an id counter for reverse lenses, a set of drivers, and a handle to the transactions host.
The Root Scope
A scope is where nodes live. It holds the list of nodes built into it, in build order, and the node it hangs off, its parent node. The root scope has no parent.
{
nodes: [], // the nodes built into this scope, in build order
parentNode: undefined, // the node this scope hangs off, if any
};
_scopeCreate opens one. It makes a fresh scope, remembers its parent node, and points the current scope at
it. Nodes built by the callback then land inside. It runs the callback, then restores the scope that was current
before. It returns the new scope object.
Reactive._scopeCreate = (parentNode, callback) => {
const scope = { nodes: [], parentNode };
const previousScope = Reactive._currentScope;
Reactive._currentScope = scope;
try {
callback();
} finally {
Reactive._currentScope = previousScope;
}
return scope;
};
Two ambient values carry the build context, so a call site names neither the root nor the scope it builds into:
Reactive._currentRoot = undefined;
Reactive._currentScope = undefined;
Reactive.Root
To run a program, make a fresh root, point _currentRoot at it, then open the root scope with
_scopeCreate and store it on the root. That scope has no parent node, and the program's calls populate
it. When the program returns, Reactive.Root restores the previous root and returns the finished root.
Reactive.Root = (programCallback) => {
const previousRoot = Reactive._currentRoot;
const root = {
rootScope: undefined,
};
Reactive._currentRoot = root;
try {
root.rootScope = Reactive._scopeCreate(undefined, programCallback);
return root;
} finally {
Reactive._currentRoot = previousRoot;
}
};
Running It
With nothing to build yet, a program is an empty function. The root it returns holds one empty scope:
const root = Reactive.Root(() => {});
root.rootScope; // { nodes: [], parentNode: undefined } the root scope
root.rootScope.nodes; // [] nothing built yet
Next Steps
A program is now a root that holds one empty scope. Next, Values adds the first nodes,
Constant and State, each an entry inside that scope.