/** * Copyright 2014-2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule ReactChildReconciler * @typechecks static-only */ 'use strict'; var ReactReconciler = require("./ReactReconciler"); var flattenChildren = require("./flattenChildren"); var instantiateReactComponent = require("./instantiateReactComponent"); var shouldUpdateReactComponent = require("./shouldUpdateReactComponent"); /** * ReactChildReconciler provides helpers for initializing or updating a set of * children. Its output is suitable for passing it onto ReactMultiChild which * does diffed reordering and insertion. */ var ReactChildReconciler = { /** * 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} nestedChildNodes Nested child maps. * @return {?object} A set of child instances. * @internal */ instantiateChildren: function(nestedChildNodes, transaction, context) { var children = flattenChildren(nestedChildNodes); for (var name in children) { if (children.hasOwnProperty(name)) { var child = children[name]; // The rendered children must be turned into instances as they're // mounted. var childInstance = instantiateReactComponent(child, null); children[name] = childInstance; } } return children; }, /** * Updates the rendered children and returns a new set of children. * * @param {?object} prevChildren Previously initialized set of children. * @param {?object} nextNestedChildNodes Nested child maps. * @param {ReactReconcileTransaction} transaction * @param {object} context * @return {?object} A new set of child instances. * @internal */ updateChildren: function( prevChildren, nextNestedChildNodes, transaction, context) { // We currently don't have a way to track moves here but if we use iterators // instead of for..in we can zip the iterators and check if an item has // moved. // TODO: If nothing has changed, return the prevChildren object so that we // can quickly bailout if nothing has changed. var nextChildren = flattenChildren(nextNestedChildNodes); if (!nextChildren && !prevChildren) { return null; } var name; for (name in nextChildren) { if (!nextChildren.hasOwnProperty(name)) { continue; } var prevChild = prevChildren && prevChildren[name]; var prevElement = prevChild && prevChild._currentElement; var nextElement = nextChildren[name]; if (shouldUpdateReactComponent(prevElement, nextElement)) { ReactReconciler.receiveComponent( prevChild, nextElement, transaction, context ); nextChildren[name] = prevChild; } else { if (prevChild) { ReactReconciler.unmountComponent(prevChild, name); } // The child must be instantiated before it's mounted. var nextChildInstance = instantiateReactComponent( nextElement, null ); nextChildren[name] = nextChildInstance; } } // Unmount children that are no longer present. for (name in prevChildren) { if (prevChildren.hasOwnProperty(name) && !(nextChildren && nextChildren.hasOwnProperty(name))) { ReactReconciler.unmountComponent(prevChildren[name]); } } return nextChildren; }, /** * Unmounts all rendered children. This should be used to clean up children * when this component is unmounted. * * @param {?object} renderedChildren Previously initialized set of children. * @internal */ unmountChildren: function(renderedChildren) { for (var name in renderedChildren) { var renderedChild = renderedChildren[name]; ReactReconciler.unmountComponent(renderedChild); } } }; module.exports = ReactChildReconciler;