-
Notifications
You must be signed in to change notification settings - Fork 17
Add API for nesting reconcilers #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I think it's possible to achieve that by moving most of the update logic outside of module Make = (OutputTree: OutputTree) => {
module GlobalState = {
let debug = ref(true);
let componentKeyCounter = ref(0);
let reset = () => {
debug := true;
componentKeyCounter := 0;
};
/**
* Use physical equality to recognize that an element was added to the list
* of children.
* Note: this currently does not check for pending updates on components in
* the list.
*/
let useTailHack = ref(false);
};
module Key = {
type t = int;
let equal = (==);
let none = (-1);
let dynamicKeyMagicNumber = 0;
let create = () => {
incr(GlobalState.componentKeyCounter);
GlobalState.componentKeyCounter^;
};
};
- type internalOutputNode =
- | Node(OutputTree.node)
- | UpdatedNode(OutputTree.node, OutputTree.node);
- type outputNodeContainer = Lazy.t(internalOutputNode);
- type outputNodeGroup = list(outputNodeContainer);
- type id('a) = ..;
- type instance('hooks, 'initialHooks, 'elementType, 'outputNode) = {
- hooks: Hooks.state('hooks, unit),
- component: component('hooks, 'initialHooks, 'elementType, 'outputNode),
- element,
- instanceSubForest: instanceForest,
- subElements: 'elementType,
- hostInstance: 'outputNode,
- }
- and element =
- | Element(component('hooks, 'initialHooks, 'elementType, 'outputNode))
- : element
- and syntheticElement =
- | Flat(element)
- | Nested(list(syntheticElement))
- and outputTreeElement = {
- make: unit => OutputTree.node,
- configureInstance:
- (~isFirstRender: bool, OutputTree.node) => OutputTree.node,
- children: syntheticElement,
- }
- and elementType('elementType, 'outputNode) =
- | Host: elementType(outputTreeElement, outputNodeContainer)
- | React: elementType(syntheticElement, outputNodeGroup)
- and instanceForest =
- | IFlat(opaqueInstance)
- | INested(list(instanceForest), int /*subtree size*/)
- and component('hooks, 'initialHooks, 'elementType, 'outputNode) = {
- debugName: string,
- key: int,
- elementType: elementType('elementType, 'outputNode),
- id: id(instance('hooks, 'initialHooks, 'elementType, 'outputNode)),
- eq:
- 'a.
- (
- 'a,
- id('a),
- id(instance('hooks, 'initialHooks, 'elementType, 'outputNode))
- ) =>
- option(instance('hooks, 'initialHooks, 'elementType, 'outputNode)),
-
- render:
- Hooks.t('hooks, unit, 'initialHooks, 'initialHooks) =>
- (Hooks.t(unit, unit, 'hooks, unit), 'elementType),
- }
- and opaqueInstance =
- | Instance(instance('hooks, 'initialHooks, 'elementType, 'outputNode))
- : opaqueInstance;
-
- type renderedElement = {
- nearestHostOutputNode: outputNodeContainer,
- instanceForest,
- enqueuedEffects: list(list(unit => unit)),
- };
-
- type opaqueInstanceUpdate = {
- nearestHostOutputNode: outputNodeContainer,
- opaqueInstance,
- enqueuedEffects: list(list(unit => unit)),
- };
}; NextWe can simply move it out of the functor and add a generic type parameter for the module type OutputTree = {
type node;
let markAsStale: unit => unit;
let insertNode: (~parent: node, ~child: node, ~position: int) => node;
let deleteNode: (~parent: node, ~child: node, ~position: int) => node;
let moveNode: (~parent: node, ~child: node, ~from: int, ~to_: int) => node;
};
+ type internalOutputNode('outputTreeNode) =
+ | Node('outputTreeNode)
+ | UpdatedNode('outputTreeNode, 'outputTreeNode);
+ type outputNodeContainer('outputTreeNode) =
+ Lazy.t(internalOutputNode('outputTreeNode));
+ type outputNodeGroup('outputTreeNode) =
+ list(outputNodeContainer('outputTreeNode));
+ type id('a) = ..;
+ type instance(
+ 'hooks,
+ 'initialHooks,
+ 'elementType,
+ 'outputNode,
+ 'outputTreeNode,
+ ) = {
+ hooks: Hooks.state('hooks, unit),
+ component:
+ component(
+ 'hooks,
+ 'initialHooks,
+ 'elementType,
+ 'outputNode,
+ 'outputTreeNode,
+ ),
+ element,
+ instanceSubForest: instanceForest,
+ subElements: 'elementType,
+ hostInstance: 'outputNode,
+ }
+ and element =
+ | Element(
+ component(
+ 'hooks,
+ 'initialHooks,
+ 'elementType,
+ 'outputNode,
+ 'outputTreeNode,
+ ),
+ )
+ : element
+ and syntheticElement =
+ | Flat(element)
+ | Nested(list(syntheticElement))
+ and outputTreeElement('outputTreeNode) = {
+ make: unit => 'outputTreeNode,
+ configureInstance:
+ (~isFirstRender: bool, 'outputTreeNode) => 'outputTreeNode,
+ children: syntheticElement,
+ }
+ and elementType('elementType, 'outputNode, 'outputTreeNode) =
+ | Host: elementType(
+ outputTreeElement('outputTreeNode),
+ outputNodeContainer('outputTreeNode),
+ 'outputTreeNode,
+ )
+ | React: elementType(
+ syntheticElement,
+ outputNodeGroup('outputTreeNode),
+ 'outputTreeNode,
+ )
+ and instanceForest =
+ | IFlat(opaqueInstance)
+ | INested(list(instanceForest), int /*subtree size*/)
+ and component(
+ 'hooks,
+ 'initialHooks,
+ 'elementType,
+ 'outputNode,
+ 'outputTreeNode,
+ ) = {
+ debugName: string,
+ key: int,
+ elementType: elementType('elementType, 'outputNode, 'outputTreeNode),
+ id:
+ id(
+ instance(
+ 'hooks,
+ 'initialHooks,
+ 'elementType,
+ 'outputNode,
+ 'outputTreeNode,
+ ),
+ ),
+ eq:
+ 'a.
+ (
+ 'a,
+ id('a),
+ id(
+ instance(
+ 'hooks,
+ 'initialHooks,
+ 'elementType,
+ 'outputNode,
+ 'outputTreeNode,
+ ),
+ )
+ ) =>
+ option(
+ instance(
+ 'hooks,
+ 'initialHooks,
+ 'elementType,
+ 'outputNode,
+ 'outputTreeNode,
+ ),
+ ),
+
+ render:
+ Hooks.t('hooks, unit, 'initialHooks, 'initialHooks) =>
+ (Hooks.t(unit, unit, 'hooks, unit), 'elementType),
+ }
+ and opaqueInstance =
+ | Instance(
+ instance(
+ 'hooks,
+ 'initialHooks,
+ 'elementType,
+ 'outputNode,
+ 'outputTreeNode,
+ ),
+ )
+ : opaqueInstance;
+
+ type renderedElement('outputTreeNode) = {
+ nearestHostOutputNode: outputNodeContainer('outputTreeNode),
+ instanceForest,
+ enqueuedEffects: list(list(unit => unit)),
+ };
+
+ type opaqueInstanceUpdate('outputTreeNode) = {
+ nearestHostOutputNode: outputNodeContainer('outputTreeNode),
+ opaqueInstance,
+ enqueuedEffects: list(list(unit => unit)),
+ };
module Make = (OutputTree: OutputTree) => {
module GlobalState = {
let debug = ref(true);
let componentKeyCounter = ref(0);
let reset = () => {
debug := true;
componentKeyCounter := 0;
};
/**
* Use physical equality to recognize that an element was added to the list
* of children.
* Note: this currently does not check for pending updates on components in
* the list.
*/
let useTailHack = ref(false);
};
module Key = {
type t = int;
let equal = (==);
let none = (-1);
let dynamicKeyMagicNumber = 0;
let create = () => {
incr(GlobalState.componentKeyCounter);
GlobalState.componentKeyCounter^;
};
};
}; ResultIt'll essentially allow us to nest any The only unsolved problem here is that we don't have a way of defining a context for the OutputTree operations. If we simply move the types and related functions out of the functor,
It cannot work - there's no way to mount a |
There are two issues with nesting reconcilers now:
The solution here is to probably change the architecture so that there'll be one reconciler per app with a different mechanism to define output nodes. It should solve also other problems with naming etc.
The text was updated successfully, but these errors were encountered: