Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| /** | |
| * Copyright 2014-present, 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 | |
| */ | |
| 'use strict'; | |
| var ReactReconciler = require('ReactReconciler'); | |
| var instantiateReactComponent = require('instantiateReactComponent'); | |
| var KeyEscapeUtils = require('KeyEscapeUtils'); | |
| var shouldUpdateReactComponent = require('shouldUpdateReactComponent'); | |
| var traverseAllChildren = require('traverseAllChildren'); | |
| var warning = require('warning'); | |
| var ReactComponentTreeHook; | |
| if ( | |
| typeof process !== 'undefined' && | |
| process.env && | |
| process.env.NODE_ENV === 'test' | |
| ) { | |
| // Temporary hack. | |
| // Inline requires don't work well with Jest: | |
| // https://github.com/facebook/react/issues/7240 | |
| // Remove the inline requires when we don't need them anymore: | |
| // https://github.com/facebook/react/pull/7178 | |
| ReactComponentTreeHook = require('ReactComponentTreeHook'); | |
| } | |
| function instantiateChild(childInstances, child, name, selfDebugID) { | |
| // We found a component instance. | |
| var keyUnique = (childInstances[name] === undefined); | |
| if (__DEV__) { | |
| if (!ReactComponentTreeHook) { | |
| ReactComponentTreeHook = require('ReactComponentTreeHook'); | |
| } | |
| if (!keyUnique) { | |
| warning( | |
| false, | |
| 'flattenChildren(...): Encountered two children with the same key, ' + | |
| '`%s`. Child keys must be unique; when two children share a key, only ' + | |
| 'the first child will be used.%s', | |
| KeyEscapeUtils.unescape(name), | |
| ReactComponentTreeHook.getStackAddendumByID(selfDebugID) | |
| ); | |
| } | |
| } | |
| if (child != null && keyUnique) { | |
| childInstances[name] = instantiateReactComponent(child, true); | |
| } | |
| } | |
| /** | |
| * 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, | |
| selfDebugID // 0 in production and for roots | |
| ) { | |
| if (nestedChildNodes == null) { | |
| return null; | |
| } | |
| var childInstances = {}; | |
| if (__DEV__) { | |
| traverseAllChildren( | |
| nestedChildNodes, | |
| (childInsts, child, name) => instantiateChild( | |
| childInsts, | |
| child, | |
| name, | |
| selfDebugID | |
| ), | |
| childInstances | |
| ); | |
| } else { | |
| traverseAllChildren(nestedChildNodes, instantiateChild, childInstances); | |
| } | |
| return childInstances; | |
| }, | |
| /** | |
| * Updates the rendered children and returns a new set of children. | |
| * | |
| * @param {?object} prevChildren Previously initialized set of children. | |
| * @param {?object} nextChildren Flat child element maps. | |
| * @param {ReactReconcileTransaction} transaction | |
| * @param {object} context | |
| * @return {?object} A new set of child instances. | |
| * @internal | |
| */ | |
| updateChildren: function( | |
| prevChildren, | |
| nextChildren, | |
| mountImages, | |
| removedNodes, | |
| transaction, | |
| hostParent, | |
| hostContainerInfo, | |
| context, | |
| selfDebugID // 0 in production and for roots | |
| ) { | |
| // 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. | |
| if (!nextChildren && !prevChildren) { | |
| return; | |
| } | |
| var name; | |
| var prevChild; | |
| for (name in nextChildren) { | |
| if (!nextChildren.hasOwnProperty(name)) { | |
| continue; | |
| } | |
| prevChild = prevChildren && prevChildren[name]; | |
| var prevElement = prevChild && prevChild._currentElement; | |
| var nextElement = nextChildren[name]; | |
| if (prevChild != null && | |
| shouldUpdateReactComponent(prevElement, nextElement)) { | |
| ReactReconciler.receiveComponent( | |
| prevChild, nextElement, transaction, context | |
| ); | |
| nextChildren[name] = prevChild; | |
| } else { | |
| if (prevChild) { | |
| removedNodes[name] = ReactReconciler.getHostNode(prevChild); | |
| ReactReconciler.unmountComponent(prevChild, false); | |
| } | |
| // The child must be instantiated before it's mounted. | |
| var nextChildInstance = instantiateReactComponent(nextElement, true); | |
| nextChildren[name] = nextChildInstance; | |
| // Creating mount image now ensures refs are resolved in right order | |
| // (see https://github.com/facebook/react/pull/7101 for explanation). | |
| var nextChildMountImage = ReactReconciler.mountComponent( | |
| nextChildInstance, | |
| transaction, | |
| hostParent, | |
| hostContainerInfo, | |
| context, | |
| selfDebugID | |
| ); | |
| mountImages.push(nextChildMountImage); | |
| } | |
| } | |
| // Unmount children that are no longer present. | |
| for (name in prevChildren) { | |
| if (prevChildren.hasOwnProperty(name) && | |
| !(nextChildren && nextChildren.hasOwnProperty(name))) { | |
| prevChild = prevChildren[name]; | |
| removedNodes[name] = ReactReconciler.getHostNode(prevChild); | |
| ReactReconciler.unmountComponent(prevChild, false); | |
| } | |
| } | |
| }, | |
| /** | |
| * 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, safely) { | |
| for (var name in renderedChildren) { | |
| if (renderedChildren.hasOwnProperty(name)) { | |
| var renderedChild = renderedChildren[name]; | |
| ReactReconciler.unmountComponent(renderedChild, safely); | |
| } | |
| } | |
| }, | |
| }; | |
| module.exports = ReactChildReconciler; |