@samitouri / QOS-React-2 / commits / 53d8bbddc7

Add React.Children.toArray

Ben Alpert committed Apr 11, 2015 at 00:55 UTC 53d8bbddc7322f165b966f862043881ac31583a9
4 files changed +85
src/isomorphic/ReactIsomorphic.js
+1
@@ -40,6 +40,7 @@ var React = {
40 map: ReactChildren.map,
41 forEach: ReactChildren.forEach,
42 count: ReactChildren.count,
43 + toArray: ReactChildren.toArray,
44 only: onlyChild,
45 },
46
src/isomorphic/children/ReactChildren.js
+32
@@ -12,6 +12,7 @@
12 'use strict';
13
14 var PooledClass = require('PooledClass');
15 +var ReactElement = require('ReactElement');
16 var ReactFragment = require('ReactFragment');
17
18 var traverseAllChildren = require('traverseAllChildren');
@@ -20,6 +21,7 @@ var warning = require('warning');
21 var twoArgumentPooler = PooledClass.twoArgumentPooler;
22 var threeArgumentPooler = PooledClass.threeArgumentPooler;
23
24 +
25 /**
26 * PooledClass representing the bookkeeping associated with performing a child
27 * traversal. Allows avoiding binding callbacks.
@@ -61,6 +63,7 @@ function forEachChildren(children, forEachFunc, forEachContext) {
63 ForEachBookKeeping.release(traverseContext);
64 }
65
66 +
67 /**
68 * PooledClass representing the bookkeeping associated with performing a child
69 * mapping. Allows avoiding binding callbacks.
@@ -126,6 +129,7 @@ function mapChildren(children, func, context) {
129 return ReactFragment.create(mapResult);
130 }
131
132 +
133 function forEachSingleChildDummy(traverseContext, child, name) {
134 return null;
135 }
@@ -141,10 +145,38 @@ function countChildren(children, context) {
145 return traverseAllChildren(children, forEachSingleChildDummy, null);
146 }
147
148 +
149 +function pushSingleChildToArray(traverseContext, child, name, i) {
150 + if (child == null) {
151 + return;
152 + }
153 +
154 + var result = traverseContext;
155 +
156 + if (ReactElement.isValidElement(child)) {
157 + child = ReactElement.cloneAndReplaceKey(child, name);
158 + }
159 + // For text components, leave unkeyed
160 +
161 + result.push(child);
162 +}
163 +
164 +/**
165 + * Flatten a children object (typically specified as `props.children`) and
166 + * return an array with appropriately re-keyed children.
167 + */
168 +function toArray(children) {
169 + var result = [];
170 + traverseAllChildren(children, pushSingleChildToArray, result);
171 + return result;
172 +}
173 +
174 +
175 var ReactChildren = {
176 forEach: forEachChildren,
177 map: mapChildren,
178 count: countChildren,
179 + toArray: toArray,
180 };
181
182 module.exports = ReactChildren;
src/isomorphic/children/__tests__/ReactChildren-test.js
+38
@@ -458,4 +458,42 @@ describe('ReactChildren', function() {
458 expect(console.error.calls[1].args[0]).toContain('is an immutable opaque');
459 });
460
461 + it('should flatten children to an array', function() {
462 + expect(ReactChildren.toArray(undefined)).toEqual([]);
463 + expect(ReactChildren.toArray(null)).toEqual([]);
464 +
465 + expect(ReactChildren.toArray(<div />).length).toBe(1);
466 + expect(ReactChildren.toArray([<div />]).length).toBe(1);
467 + expect(
468 + ReactChildren.toArray(<div />)[0].key
469 + ).toBe(
470 + ReactChildren.toArray([<div />])[0].key
471 + );
472 +
473 + var flattened = ReactChildren.toArray([
474 + [<div key="apple" />, <div key="banana" />, <div key="camel" />],
475 + [<div key="banana" />, <div key="camel" />, <div key="deli" />],
476 + ]);
477 + expect(flattened.length).toBe(6);
478 + expect(flattened[1].key).toContain('banana');
479 + expect(flattened[3].key).toContain('banana');
480 + expect(flattened[1].key).not.toBe(flattened[3].key);
481 +
482 + var reversed = ReactChildren.toArray([
483 + [<div key="camel" />, <div key="banana" />, <div key="apple" />],
484 + [<div key="deli" />, <div key="camel" />, <div key="banana" />],
485 + ]);
486 + expect(flattened[0].key).toBe(reversed[2].key);
487 + expect(flattened[1].key).toBe(reversed[1].key);
488 + expect(flattened[2].key).toBe(reversed[0].key);
489 + expect(flattened[3].key).toBe(reversed[5].key);
490 + expect(flattened[4].key).toBe(reversed[4].key);
491 + expect(flattened[5].key).toBe(reversed[3].key);
492 +
493 + // null/undefined/bool are all omitted
494 + expect(ReactChildren.toArray([1, 'two', null, undefined, true])).toEqual(
495 + [1, 'two']
496 + );
497 + });
498 +
499 });
src/isomorphic/classic/element/ReactElement.js
+14
@@ -155,6 +155,20 @@ ReactElement.createFactory = function(type) {
155 return factory;
156 };
157
158 +ReactElement.cloneAndReplaceKey = function(oldElement, newKey) {
159 + var newElement = new ReactElement(
160 + oldElement.type,
161 + newKey,
162 + oldElement.ref,
163 + oldElement.self,
164 + oldElement.source,
165 + oldElement._owner,
166 + oldElement.props
167 + );
168 +
169 + return newElement;
170 +};
171 +
172 ReactElement.cloneAndReplaceProps = function(oldElement, newProps) {
173 var newElement = new ReactElement(
174 oldElement.type,