Support `children` and `ref` for `cloneWithProps()`
We're not handling these correctly.
Pete Hunt committed
Jan 30, 2014 at 14:50 UTC
4cbc4b58f6c10a2557b0da4dc519c932f167efe3
3 files changed
+81
-2
src/core/ReactPropTransferer.js
+2
@@ -42,6 +42,8 @@ function createTransferStrategy(mergeStrategy) {
42
43
/**
44
* Transfer strategies dictate how props are transferred by `transferPropsTo`.
45
+ * NOTE: if you add any more exceptions to this list you should be sure to
46
+ * update `cloneWithProps()` accordingly.
47
*/
48
var TransferStrategies = {
49
/**
src/utils/__tests__/cloneWithProps-test.js
+52
@@ -126,4 +126,56 @@ describe('cloneWithProps', function() {
126
cloneWithProps(<Component />, {key: 'xyz'})
127
);
128
});
129
+
130
+ it('should transfer children', function() {
131
+ var Component = React.createClass({
132
+ render: function() {
133
+ expect(this.props.children).toBe('xyz');
134
+ return <div />;
135
+ }
136
+ });
137
+
138
+ ReactTestUtils.renderIntoDocument(
139
+ cloneWithProps(<Component />, {children: 'xyz'})
140
+ );
141
+ });
142
+
143
+ it('should shallow clone children', function() {
144
+ var Component = React.createClass({
145
+ render: function() {
146
+ expect(this.props.children).toBe('xyz');
147
+ return <div />;
148
+ }
149
+ });
150
+
151
+ ReactTestUtils.renderIntoDocument(
152
+ cloneWithProps(<Component>xyz</Component>, {})
153
+ );
154
+ });
155
+
156
+ it('should support keys and refs', function() {
157
+ var Component = React.createClass({
158
+ render: function() {
159
+ expect(this.props.key).toBe('xyz');
160
+ expect(this.props.ref).toBe('xyz');
161
+ return <div />;
162
+ }
163
+ });
164
+
165
+ var Parent = React.createClass({
166
+ render: function() {
167
+ var clone =
168
+ cloneWithProps(this.props.children, {key: 'xyz', ref: 'xyz'});
169
+ return <div>{clone}</div>;
170
+ }
171
+ });
172
+
173
+ var Grandparent = React.createClass({
174
+ render: function() {
175
+ return <Parent><Component key="abc" ref="abc" /></Parent>;
176
+ }
177
+ });
178
+
179
+ ReactTestUtils.renderIntoDocument(<Grandparent />);
180
+ });
181
});
src/utils/cloneWithProps.js
+27
-2
@@ -21,6 +21,14 @@
21
22
var ReactPropTransferer = require('ReactPropTransferer');
23
24
+var keyMirror = require('keyMirror');
25
+
26
+var SpecialPropsToTransfer = keyMirror({
27
+ key: null,
28
+ children: null,
29
+ ref: null
30
+});
31
+
32
/**
33
* Sometimes you want to change the props of a child passed to you. Usually
34
* this is to add a CSS class.
@@ -42,10 +50,27 @@ function cloneWithProps(child, props) {
50
}
51
52
var newProps = ReactPropTransferer.mergeProps(child.props, props);
45
- // ReactPropTransferer does not transfer the `key` prop so do it manually.
46
- if (props.key) {
53
+
54
+ // ReactPropTransferer does not transfer the `key` prop so do it manually. Do
55
+ // not transfer it from the original component.
56
+ if (props.hasOwnProperty(SpecialPropsToTransfer.key)) {
57
newProps.key = props.key;
58
}
59
+
60
+ // ReactPropTransferer does not transfer the `children` prop. Transfer it
61
+ // from `props` if it exists, otherwise use `child.props.children` if it is
62
+ // provided.
63
+ if (props.hasOwnProperty(SpecialPropsToTransfer.children)) {
64
+ newProps.children = props.children;
65
+ } else if (child.props.hasOwnProperty(SpecialPropsToTransfer.children)) {
66
+ newProps.children = child.props.children;
67
+ }
68
+
69
+ // ReactPropTransferer does not transfer `ref` so do it manually.
70
+ if (props.hasOwnProperty(SpecialPropsToTransfer.ref)) {
71
+ newProps.ref = props.ref;
72
+ }
73
+
74
return child.constructor.ConvenienceConstructor(newProps);
75
}
76