You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
126 lines
4.1 KiB
126 lines
4.1 KiB
10 years ago
|
/**
|
||
|
* 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;
|