@samitouri / QOS-React-2 / commits / e1fe13d0cb
Fork 0

The library for web and native user interfaces.

Pass multiple children in JSX as additional arguments

This is an alternative to D809298. In normal usage you'd end up with a single flat array in props.children.

CommitSyncScript committed Jun 13, 2013 at 16:33 UTC e1fe13d0cbb6063594a0b9dc712a8ee6006bb2e3
3 files changed +171 -12
src/core/__tests__/ReactComponentFlattenChildren-test.js new
+159
@@ -0,0 +1,159 @@
1 +/**
2 + * Copyright 2013 Facebook, Inc.
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + *
16 + * @jsx React.DOM
17 + * @emails react-core
18 + */
19 +
20 +"use strict";
21 +
22 +var React;
23 +
24 +var Fake;
25 +
26 +var singleChild = function(children) {
27 + return (<Fake>{children}</Fake>).props.children;
28 +};
29 +
30 +var multiChild = function(child1, child2, child3, child4) {
31 + return (<Fake>{child1} {child2} {child3}{child4}</Fake>).props.children;
32 +};
33 +
34 +
35 +describe('ReactComponentFlatten', function() {
36 + beforeEach(function() {
37 + require('mock-modules').dumpCache();
38 + React = require('React');
39 + var ReactComponent = require('ReactComponent');
40 + var copyProperties = require('copyProperties');
41 + var Constructor = function() {};
42 + copyProperties(Constructor.prototype, ReactComponent.Mixin);
43 + Fake = function() {
44 + var instance = new Constructor();
45 + instance.construct.apply(instance, arguments);
46 + return instance;
47 + };
48 + });
49 +
50 + it("should reuse a flat array", function() {
51 + var children = [
52 + <div key="foo" />,
53 + <div key="bar" />
54 + ];
55 +
56 + var flat = singleChild(children);
57 +
58 + expect(flat).toBe(children);
59 + expect(flat[0]._key).toEqual('0:foo');
60 + expect(flat[1]._key).toEqual('0:bar');
61 + });
62 +
63 + it("should collapse a sparse array", function() {
64 + var children = [
65 + null,
66 + <div key="foo" />,
67 + <div key="bar" />
68 + ];
69 +
70 + var flat = singleChild(children);
71 +
72 + expect(flat).not.toBe(children);
73 + expect(flat.length).toEqual(2);
74 + expect(flat[0]._key).toEqual('0:foo');
75 + expect(flat[1]._key).toEqual('0:bar');
76 + });
77 +
78 + it("should collapse a nested array into a flat array", function() {
79 + var flat = multiChild(
80 + null,
81 + <div key="foo" />,
82 + [<div key="bar" />, null]
83 + );
84 +
85 + expect(flat.length).toEqual(2);
86 + expect(flat[0]._key).toEqual('foo');
87 + expect(flat[1]._key).toEqual('2:bar');
88 + });
89 +
90 + it("should use retain key index despite static empty values", function() {
91 + // TODO: Wrap in another single child (currently breaks)
92 +
93 + var before = multiChild(
94 + <div />,
95 + <div />,
96 + [<div key="foo" />],
97 + [<div key="foo" />]
98 + );
99 +
100 + var after = multiChild(
101 + null,
102 + <div />,
103 + null,
104 + [<div key="foo" />]
105 + );
106 +
107 + expect(before.length).toEqual(4);
108 + expect(after.length).toEqual(2);
109 + expect(before[1]._key).toEqual(after[0]._key);
110 + expect(before[3]._key).toEqual(after[1]._key);
111 + });
112 +
113 + it("should assign idempotent keys for extra flattening layers", function() {
114 + var flat = multiChild(
115 + null,
116 + [null, <div key="FOO" />],
117 + false
118 + );
119 +
120 + var preFlat = multiChild(
121 + null,
122 + singleChild([null, <div key="FOO" />]),
123 + false
124 + );
125 +
126 + expect(flat.length).toBe(1);
127 + expect(preFlat.length).toBe(1);
128 + expect(preFlat[0]._key).toBe(flat[0]._key);
129 + });
130 +
131 + it("should assign idempotent strings through flattening", function() {
132 + var children = [
133 + 'FOO',
134 + 'BAR'
135 + ];
136 + var flat = singleChild(children);
137 + var wrappedFlat = multiChild(null, flat);
138 + expect(flat).toBe(children);
139 + expect(wrappedFlat.length).toBe(2);
140 + expect(wrappedFlat[0]).toBe(flat[0]);
141 + expect(wrappedFlat[1]).toBe(flat[1]);
142 + });
143 +
144 + it("cannot keep keys unique when children are unboxed", function() {
145 + // This is a case that difficult to solve and should not actually be solved.
146 + var children1 = [<div key="foo" />];
147 + var children2 = [<div key="foo" />];
148 + var flat1 = singleChild(children1);
149 + var flat2 = singleChild(children2);
150 + // There's no way to tell flat1[0] and flat2[0] apart.
151 + var mergedChildren = [flat1[0], flat2[0]];
152 + var newChildren = multiChild(mergedChildren);
153 + expect(newChildren.length).toBe(2);
154 + expect(newChildren[0]._key).toBe(newChildren[1]._key);
155 + });
156 +
157 +});
158 +
159 +
src/core/__tests__/ReactIdentity-test.js
+8 -8
@@ -67,8 +67,8 @@ describe('ReactIdentity', function() {
67 React.renderComponent(instance, document.createElement('div'));
68 var node = instance.getDOMNode();
69 reactComponentExpect(instance).toBeDOMComponentWithChildCount(2);
70 - checkId(node.childNodes[0], '.reactRoot[0].[0:apple]');
71 - checkId(node.childNodes[1], '.reactRoot[0].[0:banana]');
70 + checkId(node.childNodes[0], '.reactRoot[0].[apple]');
71 + checkId(node.childNodes[1], '.reactRoot[0].[banana]');
72 });
73
74 it('should use instance identity', function() {
@@ -89,15 +89,15 @@ describe('ReactIdentity', function() {
89 React.renderComponent(instance, document.createElement('div'));
90 var node = instance.getDOMNode();
91 reactComponentExpect(instance).toBeDOMComponentWithChildCount(3);
92 - checkId(node.childNodes[0], '.reactRoot[0].[0:wrap1]');
92 + checkId(node.childNodes[0], '.reactRoot[0].[wrap1]');
93 checkId(
94 node.childNodes[0].firstChild,
95 - '.reactRoot[0].[0:wrap1].[0:squirrel]'
95 + '.reactRoot[0].[wrap1].[0:squirrel]'
96 );
97 - checkId(node.childNodes[1], '.reactRoot[0].[0:wrap2]');
98 - checkId(node.childNodes[1].firstChild, '.reactRoot[0].[0:wrap2].[0:bunny]');
99 - checkId(node.childNodes[2], '.reactRoot[0].[0:2]');
100 - checkId(node.childNodes[2].firstChild, '.reactRoot[0].[0:2].[0:chipmunk]');
97 + checkId(node.childNodes[1], '.reactRoot[0].[wrap2]');
98 + checkId(node.childNodes[1].firstChild, '.reactRoot[0].[wrap2].[0:bunny]');
99 + checkId(node.childNodes[2], '.reactRoot[0].[2]');
100 + checkId(node.childNodes[2].firstChild, '.reactRoot[0].[2].[0:chipmunk]');
101 });
102
103 it('should let restructured components retain their uniqueness', function() {
src/utils/__tests__/mapChildren-test.js
+4 -4
@@ -122,12 +122,12 @@ describe('mapChildren', function() {
122 .instance();
123
124 expect(mapFn.calls.length).toBe(3);
125 - expect(mapFn).toHaveBeenCalledWith(kidOne, '0:one', 0);
126 - expect(mapFn).toHaveBeenCalledWith(kidTwo, '0:two', 1);
127 - expect(mapFn).toHaveBeenCalledWith(kidThree, '0:three', 2);
125 + expect(mapFn).toHaveBeenCalledWith(kidOne, 'one', 0);
126 + expect(mapFn).toHaveBeenCalledWith(kidTwo, 'two', 1);
127 + expect(mapFn).toHaveBeenCalledWith(kidThree, 'three', 2);
128 expect(rendered.props.children).not.toEqual(instance.props.children);
129 expect(rendered.props.children).toHaveKeys([
130 - '0:0:one', '0:0:two', '0:0:three'
130 + '0:one', '0:two', '0:three'
131 ]);
132 });
133 });