@samitouri / QOS-React-2 / commits / 4cbc4b58f6

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