function mountComponent(component) {
// This will generate the DOM node that will go into the DOM. We defer to the
// component instance since it will contain the renderer specific implementation
// of what that means. This allows the Reconciler to be reused across DOM & Native.
let markup = component.mountComponent();
// React does more work here to ensure that refs work. We don't need to.
return markup;
}
function receiveComponent(component, element) {
// Shortcut! We won't do anythign if the next element is the same as the
// current one. This is unlikely in normal JSX usage, but it an optimization
// that can be unlocked with Babel's inline-element transform.
let prevElement = component._currentElement;
if (prevElement === element) {
return;
}
// Defer to the instance.
component.receiveComponent(element);
}
function createElement(type, config, children) {
// Clone the passed in config (props). In React we move some special
// props off of this object (keys, refs).
let props = Object.assign({}, config);
// Build props.children. We'll make it an array if we have more than 1.
let childCount = arguments.length - 2;
if (childCount === 1) {
props.children = children;
} else if (childCount > 1) {
props.children = Array.prototype.slice.call(arguments, 2);
}
// React Features not supported:
// - keys
// - refs
// - defaultProps (usually set here)
return {
type,
props,
};
}
function render(element, node) {
assert(Element.isValidElement(element));
// First check if we've already rendered into this node.
// If so, we'll be doing an update.
// Otherwise we'll assume this is an initial render.
if (isRoot(node)) {
update(element, node);
} else {
mount(element, node);
}
}
function mount(element, node) {
// Mark this node as a root.
node.dataset[ROOT_KEY] = rootID;
// Create the internal instance. We're assuming for now that we only have
// `Component`s being rendered at the root.
let component = instantiateComponent(element);
instancesByRootID[rootID] = component;
// This will return a DOM node. React does more work here to determine if we're remounting
// server-rendered content.
let renderedNode = Reconciler.mountComponent(component, node);
// Empty out `node` so we can put it under our control.
DOM.empty(node);
DOM.appendChild(node, renderedNode);
// Incrememnt rootID so we can track appropriately.
rootID++;
}
function update(element, node) {
// Ensure we have a valid root node
assert(node && isRoot(node));
// Find the internal instance and update it
let id = node.dataset[ROOT_KEY];
let instance = instancesByRootID[id];
if (shouldUpdateComponent(instance, element)) {
Reconciler.receiveComponent(
instance,
element
);
}
} else {
// Unmount and then mount the new one
unmountComponentAtNode(node);
mount(element, node);
}
// TODO: update
}
function shouldUpdateComponent(prevElement, nextElement) {
let prevType = typeof prevElement;
let nextType = typeof nextElement;
// Quickly allow strings.
if (prevType === 'string') {
return nextType === 'string';
}
// Otherwise look at element.type. In React we would also look at the key.
return prevElement.type === nextElement.type;
}