diff --git a/src/utils/ReactChildren.js b/src/utils/ReactChildren.js
index 49ca0ea2e0..f92e5da296 100644
--- a/src/utils/ReactChildren.js
+++ b/src/utils/ReactChildren.js
@@ -129,9 +129,25 @@ function mapChildren(children, func, context) {
return mapResult;
}
+/**
+* Count the number of children that are typically specified as
+* `props.children`.
+*/
+
+function forEachSingleChildDummy(traverseContext, child, name, i) {
+ return null;
+}
+
+function countChildren(children, context) {
+ var numberOfChildren = traverseAllChildren(children, forEachSingleChildDummy,
+ null);
+ return numberOfChildren;
+}
+
var ReactChildren = {
forEach: forEachChildren,
- map: mapChildren
+ map: mapChildren,
+ count: countChildren
};
module.exports = ReactChildren;
diff --git a/src/utils/__tests__/ReactChildren-test.js b/src/utils/__tests__/ReactChildren-test.js
index 4cfd192ed6..18f472a7ba 100644
--- a/src/utils/__tests__/ReactChildren-test.js
+++ b/src/utils/__tests__/ReactChildren-test.js
@@ -335,4 +335,67 @@ describe('ReactChildren', function() {
expect(console.warn.calls.length).toEqual(1);
expect(mapped).toEqual({'.$something': zero});
});
+
+ it('should return 0 for null children', function() {
+ var numberOfChildren = ReactChildren.count(null);
+ expect(numberOfChildren).toBe(0);
+ });
+
+ it('should return 0 for undefined children', function() {
+ var numberOfChildren = ReactChildren.count(undefined);
+ expect(numberOfChildren).toBe(0);
+ });
+
+ it('should return 1 for single child', function() {
+ var simpleKid = ;
+ var instance =
{simpleKid}
;
+ var numberOfChildren = ReactChildren.count(instance.props.children);
+ expect(numberOfChildren).toBe(1);
+ });
+
+ it('should count the number of children in flat structure', function() {
+ var zero = ;
+ var one = null;
+ var two = ;
+ var three = null;
+ var four = ;
+
+ var instance = (
+
+ {zero}
+ {one}
+ {two}
+ {three}
+ {four}
+
+ );
+ var numberOfChildren = ReactChildren.count(instance.props.children);
+ expect(numberOfChildren).toBe(5);
+ });
+
+ it('should count the number of children in nested structure', function() {
+ var zero = ;
+ var one = null;
+ var two = ;
+ var three = null;
+ var four = ;
+ var five = ;
+ // five is placed into a JS object with a key that is joined to the
+ // component key attribute.
+ // Precedence is as follows:
+ // 1. If grouped in an Object, the object key combined with `key` prop
+ // 2. If grouped in an Array, the `key` prop, falling back to array index
+
+ var instance = (
+ {
+ [{
+ firstHalfKey: [zero, one, two],
+ secondHalfKey: [three, four],
+ keyFive: five
+ }]
+ }
+ );
+ var numberOfChildren = ReactChildren.count(instance.props.children);
+ expect(numberOfChildren).toBe(6);
+ });
});
diff --git a/src/utils/traverseAllChildren.js b/src/utils/traverseAllChildren.js
index d89d4402bc..624b70c473 100644
--- a/src/utils/traverseAllChildren.js
+++ b/src/utils/traverseAllChildren.js
@@ -180,10 +180,14 @@ var traverseAllChildrenImpl =
* @param {?*} children Children tree object.
* @param {!function} callback To invoke upon traversing each child.
* @param {?*} traverseContext Context for traversal.
+ * @return {!number} The number of children in this subtree.
*/
function traverseAllChildren(children, callback, traverseContext) {
if (children !== null && children !== undefined) {
- traverseAllChildrenImpl(children, '', 0, callback, traverseContext);
+ return traverseAllChildrenImpl(children, '', 0, callback, traverseContext);
+ }
+ else {
+ return 0;
}
}