diff --git a/src/renderers/art/ReactART.js b/src/renderers/art/ReactART.js index be85e1f2389..0f102926e31 100644 --- a/src/renderers/art/ReactART.js +++ b/src/renderers/art/ReactART.js @@ -93,7 +93,7 @@ function injectAfter(parentNode, referenceNode, node) { // ContainerMixin for components that can hold ART nodes -const ContainerMixin = assign({}, ReactMultiChild.Mixin, { +const ContainerMixin = assign({}, ReactMultiChild, { /** * Moves a child component to the supplied index. @@ -144,7 +144,7 @@ const ContainerMixin = assign({}, ReactMultiChild.Mixin, { * @param {?object} nextChildren. * @param {ReactReconcileTransaction} transaction * @internal - * @override {ReactMultiChild.Mixin.updateChildren} + * @override {ReactMultiChild.updateChildren} */ updateChildren: function(nextChildren, transaction, context) { this._updateChildren(nextChildren, transaction, context); diff --git a/src/renderers/dom/shared/ReactDOMComponent.js b/src/renderers/dom/shared/ReactDOMComponent.js index b5233e021cd..88ed489f94f 100644 --- a/src/renderers/dom/shared/ReactDOMComponent.js +++ b/src/renderers/dom/shared/ReactDOMComponent.js @@ -1210,7 +1210,7 @@ ReactDOMComponent.Mixin = { Object.assign( ReactDOMComponent.prototype, ReactDOMComponent.Mixin, - ReactMultiChild.Mixin + ReactMultiChild ); module.exports = ReactDOMComponent; diff --git a/src/renderers/native/ReactNativeBaseComponent.js b/src/renderers/native/ReactNativeBaseComponent.js index 5d131739fc9..2192b019fc4 100644 --- a/src/renderers/native/ReactNativeBaseComponent.js +++ b/src/renderers/native/ReactNativeBaseComponent.js @@ -224,7 +224,7 @@ ReactNativeBaseComponent.Mixin = { */ Object.assign( ReactNativeBaseComponent.prototype, - ReactMultiChild.Mixin, + ReactMultiChild, ReactNativeBaseComponent.Mixin, NativeMethodsMixin ); diff --git a/src/renderers/shared/stack/reconciler/ReactMultiChild.js b/src/renderers/shared/stack/reconciler/ReactMultiChild.js index a0d05a76e6f..220de49f3e6 100644 --- a/src/renderers/shared/stack/reconciler/ReactMultiChild.js +++ b/src/renderers/shared/stack/reconciler/ReactMultiChild.js @@ -165,357 +165,343 @@ if (__DEV__) { } /** - * ReactMultiChild are capable of reconciling multiple children. - * - * @class ReactMultiChild - * @internal + * Provides common functionality for components that must reconcile multiple + * children. This is used by `ReactDOMComponent` to mount, update, and + * unmount child components. */ var ReactMultiChild = { - - /** - * Provides common functionality for components that must reconcile multiple - * children. This is used by `ReactDOMComponent` to mount, update, and - * unmount child components. - * - * @lends {ReactMultiChild.prototype} - */ - Mixin: { - - _reconcilerInstantiateChildren: function(nestedChildren, transaction, context) { - if (__DEV__) { - var selfDebugID = getDebugID(this); - if (this._currentElement) { - try { - ReactCurrentOwner.current = this._currentElement._owner; - return ReactChildReconciler.instantiateChildren( - nestedChildren, transaction, context, selfDebugID - ); - } finally { - ReactCurrentOwner.current = null; - } + _reconcilerInstantiateChildren: function(nestedChildren, transaction, context) { + if (__DEV__) { + var selfDebugID = getDebugID(this); + if (this._currentElement) { + try { + ReactCurrentOwner.current = this._currentElement._owner; + return ReactChildReconciler.instantiateChildren( + nestedChildren, transaction, context, selfDebugID + ); + } finally { + ReactCurrentOwner.current = null; } } - return ReactChildReconciler.instantiateChildren( - nestedChildren, transaction, context - ); - }, + } + return ReactChildReconciler.instantiateChildren( + nestedChildren, transaction, context + ); + }, - _reconcilerUpdateChildren: function( + _reconcilerUpdateChildren: function( + prevChildren, + nextNestedChildrenElements, + mountImages, + removedNodes, + transaction, + context + ) { + var nextChildren; + var selfDebugID = 0; + if (__DEV__) { + selfDebugID = getDebugID(this); + if (this._currentElement) { + try { + ReactCurrentOwner.current = this._currentElement._owner; + nextChildren = flattenChildren(nextNestedChildrenElements, selfDebugID); + } finally { + ReactCurrentOwner.current = null; + } + ReactChildReconciler.updateChildren( + prevChildren, + nextChildren, + mountImages, + removedNodes, + transaction, + this, + this._hostContainerInfo, + context, + selfDebugID + ); + return nextChildren; + } + } + nextChildren = flattenChildren(nextNestedChildrenElements, selfDebugID); + ReactChildReconciler.updateChildren( prevChildren, - nextNestedChildrenElements, + nextChildren, mountImages, removedNodes, transaction, - context - ) { - var nextChildren; - var selfDebugID = 0; - if (__DEV__) { - selfDebugID = getDebugID(this); - if (this._currentElement) { - try { - ReactCurrentOwner.current = this._currentElement._owner; - nextChildren = flattenChildren(nextNestedChildrenElements, selfDebugID); - } finally { - ReactCurrentOwner.current = null; - } - ReactChildReconciler.updateChildren( - prevChildren, - nextChildren, - mountImages, - removedNodes, - transaction, - this, - this._hostContainerInfo, - context, - selfDebugID - ); - return nextChildren; - } - } - nextChildren = flattenChildren(nextNestedChildrenElements, selfDebugID); - ReactChildReconciler.updateChildren( - prevChildren, - nextChildren, - mountImages, - removedNodes, - transaction, - this, - this._hostContainerInfo, - context, - selfDebugID - ); - return nextChildren; - }, - - /** - * Generates a "mount image" for each of the supplied children. In the case - * of `ReactDOMComponent`, a mount image is a string of markup. - * - * @param {?object} nestedChildren Nested child maps. - * @return {array} An array of mounted representations. - * @internal - */ - mountChildren: function(nestedChildren, transaction, context) { - var children = this._reconcilerInstantiateChildren( - nestedChildren, transaction, context - ); - this._renderedChildren = children; + this, + this._hostContainerInfo, + context, + selfDebugID + ); + return nextChildren; + }, - var mountImages = []; - var index = 0; - for (var name in children) { - if (children.hasOwnProperty(name)) { - var child = children[name]; - var selfDebugID = 0; - if (__DEV__) { - selfDebugID = getDebugID(this); - } - var mountImage = ReactReconciler.mountComponent( - child, - transaction, - this, - this._hostContainerInfo, - context, - selfDebugID - ); - child._mountIndex = index++; - mountImages.push(mountImage); + /** + * Generates a "mount image" for each of the supplied children. In the case + * of `ReactDOMComponent`, a mount image is a string of markup. + * + * @param {?object} nestedChildren Nested child maps. + * @return {array} An array of mounted representations. + * @internal + */ + mountChildren: function(nestedChildren, transaction, context) { + var children = this._reconcilerInstantiateChildren( + nestedChildren, transaction, context + ); + this._renderedChildren = children; + + var mountImages = []; + var index = 0; + for (var name in children) { + if (children.hasOwnProperty(name)) { + var child = children[name]; + var selfDebugID = 0; + if (__DEV__) { + selfDebugID = getDebugID(this); } + var mountImage = ReactReconciler.mountComponent( + child, + transaction, + this, + this._hostContainerInfo, + context, + selfDebugID + ); + child._mountIndex = index++; + mountImages.push(mountImage); } + } - if (__DEV__) { - setChildrenForInstrumentation.call(this, children); - } + if (__DEV__) { + setChildrenForInstrumentation.call(this, children); + } - return mountImages; - }, + return mountImages; + }, - /** - * Replaces any rendered children with a text content string. - * - * @param {string} nextContent String of content. - * @internal - */ - updateTextContent: function(nextContent) { - var prevChildren = this._renderedChildren; - // Remove any rendered children. - ReactChildReconciler.unmountChildren(prevChildren, false); - for (var name in prevChildren) { - if (prevChildren.hasOwnProperty(name)) { - invariant(false, 'updateTextContent called on non-empty component.'); - } + /** + * Replaces any rendered children with a text content string. + * + * @param {string} nextContent String of content. + * @internal + */ + updateTextContent: function(nextContent) { + var prevChildren = this._renderedChildren; + // Remove any rendered children. + ReactChildReconciler.unmountChildren(prevChildren, false); + for (var name in prevChildren) { + if (prevChildren.hasOwnProperty(name)) { + invariant(false, 'updateTextContent called on non-empty component.'); } - // Set new text content. - var updates = [makeTextContent(nextContent)]; - processQueue(this, updates); - }, + } + // Set new text content. + var updates = [makeTextContent(nextContent)]; + processQueue(this, updates); + }, - /** - * Replaces any rendered children with a markup string. - * - * @param {string} nextMarkup String of markup. - * @internal - */ - updateMarkup: function(nextMarkup) { - var prevChildren = this._renderedChildren; - // Remove any rendered children. - ReactChildReconciler.unmountChildren(prevChildren, false); - for (var name in prevChildren) { - if (prevChildren.hasOwnProperty(name)) { - invariant(false, 'updateTextContent called on non-empty component.'); - } + /** + * Replaces any rendered children with a markup string. + * + * @param {string} nextMarkup String of markup. + * @internal + */ + updateMarkup: function(nextMarkup) { + var prevChildren = this._renderedChildren; + // Remove any rendered children. + ReactChildReconciler.unmountChildren(prevChildren, false); + for (var name in prevChildren) { + if (prevChildren.hasOwnProperty(name)) { + invariant(false, 'updateTextContent called on non-empty component.'); } - var updates = [makeSetMarkup(nextMarkup)]; - processQueue(this, updates); - }, + } + var updates = [makeSetMarkup(nextMarkup)]; + processQueue(this, updates); + }, - /** - * Updates the rendered children with new children. - * - * @param {?object} nextNestedChildrenElements Nested child element maps. - * @param {ReactReconcileTransaction} transaction - * @internal - */ - updateChildren: function(nextNestedChildrenElements, transaction, context) { - // Hook used by React ART - this._updateChildren(nextNestedChildrenElements, transaction, context); - }, + /** + * Updates the rendered children with new children. + * + * @param {?object} nextNestedChildrenElements Nested child element maps. + * @param {ReactReconcileTransaction} transaction + * @internal + */ + updateChildren: function(nextNestedChildrenElements, transaction, context) { + // Hook used by React ART + this._updateChildren(nextNestedChildrenElements, transaction, context); + }, - /** - * @param {?object} nextNestedChildrenElements Nested child element maps. - * @param {ReactReconcileTransaction} transaction - * @final - * @protected - */ - _updateChildren: function(nextNestedChildrenElements, transaction, context) { - var prevChildren = this._renderedChildren; - var removedNodes = {}; - var mountImages = []; - var nextChildren = this._reconcilerUpdateChildren( - prevChildren, - nextNestedChildrenElements, - mountImages, - removedNodes, - transaction, - context - ); - if (!nextChildren && !prevChildren) { - return; + /** + * @param {?object} nextNestedChildrenElements Nested child element maps. + * @param {ReactReconcileTransaction} transaction + * @final + * @protected + */ + _updateChildren: function(nextNestedChildrenElements, transaction, context) { + var prevChildren = this._renderedChildren; + var removedNodes = {}; + var mountImages = []; + var nextChildren = this._reconcilerUpdateChildren( + prevChildren, + nextNestedChildrenElements, + mountImages, + removedNodes, + transaction, + context + ); + if (!nextChildren && !prevChildren) { + return; + } + var updates = null; + var name; + // `nextIndex` will increment for each child in `nextChildren`, but + // `lastIndex` will be the last index visited in `prevChildren`. + var nextIndex = 0; + var lastIndex = 0; + // `nextMountIndex` will increment for each newly mounted child. + var nextMountIndex = 0; + var lastPlacedNode = null; + for (name in nextChildren) { + if (!nextChildren.hasOwnProperty(name)) { + continue; } - var updates = null; - var name; - // `nextIndex` will increment for each child in `nextChildren`, but - // `lastIndex` will be the last index visited in `prevChildren`. - var nextIndex = 0; - var lastIndex = 0; - // `nextMountIndex` will increment for each newly mounted child. - var nextMountIndex = 0; - var lastPlacedNode = null; - for (name in nextChildren) { - if (!nextChildren.hasOwnProperty(name)) { - continue; - } - var prevChild = prevChildren && prevChildren[name]; - var nextChild = nextChildren[name]; - if (prevChild === nextChild) { - updates = enqueue( - updates, - this.moveChild(prevChild, lastPlacedNode, nextIndex, lastIndex) - ); + var prevChild = prevChildren && prevChildren[name]; + var nextChild = nextChildren[name]; + if (prevChild === nextChild) { + updates = enqueue( + updates, + this.moveChild(prevChild, lastPlacedNode, nextIndex, lastIndex) + ); + lastIndex = Math.max(prevChild._mountIndex, lastIndex); + prevChild._mountIndex = nextIndex; + } else { + if (prevChild) { + // Update `lastIndex` before `_mountIndex` gets unset by unmounting. lastIndex = Math.max(prevChild._mountIndex, lastIndex); - prevChild._mountIndex = nextIndex; - } else { - if (prevChild) { - // Update `lastIndex` before `_mountIndex` gets unset by unmounting. - lastIndex = Math.max(prevChild._mountIndex, lastIndex); - // The `removedNodes` loop below will actually remove the child. - } - // The child must be instantiated before it's mounted. - updates = enqueue( - updates, - this._mountChildAtIndex( - nextChild, - mountImages[nextMountIndex], - lastPlacedNode, - nextIndex, - transaction, - context - ) - ); - nextMountIndex++; - } - nextIndex++; - lastPlacedNode = ReactReconciler.getHostNode(nextChild); - } - // Remove children that are no longer present. - for (name in removedNodes) { - if (removedNodes.hasOwnProperty(name)) { - updates = enqueue( - updates, - this._unmountChild(prevChildren[name], removedNodes[name]) - ); + // The `removedNodes` loop below will actually remove the child. } + // The child must be instantiated before it's mounted. + updates = enqueue( + updates, + this._mountChildAtIndex( + nextChild, + mountImages[nextMountIndex], + lastPlacedNode, + nextIndex, + transaction, + context + ) + ); + nextMountIndex++; } - if (updates) { - processQueue(this, updates); - } - this._renderedChildren = nextChildren; - - if (__DEV__) { - setChildrenForInstrumentation.call(this, nextChildren); + nextIndex++; + lastPlacedNode = ReactReconciler.getHostNode(nextChild); + } + // Remove children that are no longer present. + for (name in removedNodes) { + if (removedNodes.hasOwnProperty(name)) { + updates = enqueue( + updates, + this._unmountChild(prevChildren[name], removedNodes[name]) + ); } - }, - - /** - * Unmounts all rendered children. This should be used to clean up children - * when this component is unmounted. It does not actually perform any - * backend operations. - * - * @internal - */ - unmountChildren: function(safely) { - var renderedChildren = this._renderedChildren; - ReactChildReconciler.unmountChildren(renderedChildren, safely); - this._renderedChildren = null; - }, + } + if (updates) { + processQueue(this, updates); + } + this._renderedChildren = nextChildren; - /** - * Moves a child component to the supplied index. - * - * @param {ReactComponent} child Component to move. - * @param {number} toIndex Destination index of the element. - * @param {number} lastIndex Last index visited of the siblings of `child`. - * @protected - */ - moveChild: function(child, afterNode, toIndex, lastIndex) { - // If the index of `child` is less than `lastIndex`, then it needs to - // be moved. Otherwise, we do not need to move it because a child will be - // inserted or moved before `child`. - if (child._mountIndex < lastIndex) { - return makeMove(child, afterNode, toIndex); - } - }, + if (__DEV__) { + setChildrenForInstrumentation.call(this, nextChildren); + } + }, - /** - * Creates a child component. - * - * @param {ReactComponent} child Component to create. - * @param {string} mountImage Markup to insert. - * @protected - */ - createChild: function(child, afterNode, mountImage) { - return makeInsertMarkup(mountImage, afterNode, child._mountIndex); - }, + /** + * Unmounts all rendered children. This should be used to clean up children + * when this component is unmounted. It does not actually perform any + * backend operations. + * + * @internal + */ + unmountChildren: function(safely) { + var renderedChildren = this._renderedChildren; + ReactChildReconciler.unmountChildren(renderedChildren, safely); + this._renderedChildren = null; + }, - /** - * Removes a child component. - * - * @param {ReactComponent} child Child to remove. - * @protected - */ - removeChild: function(child, node) { - return makeRemove(child, node); - }, + /** + * Moves a child component to the supplied index. + * + * @param {ReactComponent} child Component to move. + * @param {number} toIndex Destination index of the element. + * @param {number} lastIndex Last index visited of the siblings of `child`. + * @protected + */ + moveChild: function(child, afterNode, toIndex, lastIndex) { + // If the index of `child` is less than `lastIndex`, then it needs to + // be moved. Otherwise, we do not need to move it because a child will be + // inserted or moved before `child`. + if (child._mountIndex < lastIndex) { + return makeMove(child, afterNode, toIndex); + } + }, - /** - * Mounts a child with the supplied name. - * - * NOTE: This is part of `updateChildren` and is here for readability. - * - * @param {ReactComponent} child Component to mount. - * @param {string} name Name of the child. - * @param {number} index Index at which to insert the child. - * @param {ReactReconcileTransaction} transaction - * @private - */ - _mountChildAtIndex: function( - child, - mountImage, - afterNode, - index, - transaction, - context) { - child._mountIndex = index; - return this.createChild(child, afterNode, mountImage); - }, + /** + * Creates a child component. + * + * @param {ReactComponent} child Component to create. + * @param {string} mountImage Markup to insert. + * @protected + */ + createChild: function(child, afterNode, mountImage) { + return makeInsertMarkup(mountImage, afterNode, child._mountIndex); + }, - /** - * Unmounts a rendered child. - * - * NOTE: This is part of `updateChildren` and is here for readability. - * - * @param {ReactComponent} child Component to unmount. - * @private - */ - _unmountChild: function(child, node) { - var update = this.removeChild(child, node); - child._mountIndex = null; - return update; - }, + /** + * Removes a child component. + * + * @param {ReactComponent} child Child to remove. + * @protected + */ + removeChild: function(child, node) { + return makeRemove(child, node); + }, + /** + * Mounts a child with the supplied name. + * + * NOTE: This is part of `updateChildren` and is here for readability. + * + * @param {ReactComponent} child Component to mount. + * @param {string} name Name of the child. + * @param {number} index Index at which to insert the child. + * @param {ReactReconcileTransaction} transaction + * @private + */ + _mountChildAtIndex: function( + child, + mountImage, + afterNode, + index, + transaction, + context) { + child._mountIndex = index; + return this.createChild(child, afterNode, mountImage); }, + /** + * Unmounts a rendered child. + * + * NOTE: This is part of `updateChildren` and is here for readability. + * + * @param {ReactComponent} child Component to unmount. + * @private + */ + _unmountChild: function(child, node) { + var update = this.removeChild(child, node); + child._mountIndex = null; + return update; + }, }; module.exports = ReactMultiChild; diff --git a/src/renderers/testing/ReactTestRenderer.js b/src/renderers/testing/ReactTestRenderer.js index 50716e55f1b..ac9d1f47248 100644 --- a/src/renderers/testing/ReactTestRenderer.js +++ b/src/renderers/testing/ReactTestRenderer.js @@ -88,7 +88,7 @@ ReactTestComponent.prototype.toJSON = function() { }); return object; }; -Object.assign(ReactTestComponent.prototype, ReactMultiChild.Mixin); +Object.assign(ReactTestComponent.prototype, ReactMultiChild); // =============================================================================