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
});