Don't interpret reserved props as attributes for SVG elements
This fixes a bug introduced in #5714. The code paths are now similar to web components where we worked around the same issue in #5093. Additionally, we also skip dangerouslySetInnerHTML and suppressContentEditableWarning.
Dan Abramov committed
Mar 2, 2016 at 01:57 UTC
5eab1bbe29860e3bc262a7747aead016482b4999
2 files changed
+111
-20
src/renderers/dom/shared/ReactDOMComponent.js
+22
-15
@@ -53,9 +53,13 @@ var registrationNameModules = EventPluginRegistry.registrationNameModules;
53
// For quickly matching children type, to test if can be treated as content.
54
var CONTENT_TYPES = {'string': true, 'number': true};
55
56
-var CHILDREN = keyOf({children: null});
56
var STYLE = keyOf({style: null});
57
var HTML = keyOf({__html: null});
58
+var RESERVED_PROPS = {
59
+ children: null,
60
+ dangerouslySetInnerHTML: null,
61
+ suppressContentEditableWarning: null,
62
+};
63
64
function getDeclarationErrorAddendum(internalInstance) {
65
if (internalInstance) {
@@ -633,11 +637,13 @@ ReactDOMComponent.Mixin = {
637
}
638
var markup = null;
639
if (this._tag != null && isCustomComponent(this._tag, props)) {
636
- if (propKey !== CHILDREN) {
640
+ if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
641
markup = DOMPropertyOperations.createMarkupForCustomAttribute(propKey, propValue);
642
}
643
} else if (this._namespaceURI === DOMNamespaces.svg) {
640
- markup = DOMPropertyOperations.createMarkupForSVGAttribute(propKey, propValue);
644
+ if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
645
+ markup = DOMPropertyOperations.createMarkupForSVGAttribute(propKey, propValue);
646
+ }
647
} else {
648
markup = DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
649
}
@@ -912,20 +918,21 @@ ReactDOMComponent.Mixin = {
918
deleteListener(this, propKey);
919
}
920
} else if (isCustomComponent(this._tag, nextProps)) {
915
- if (propKey === CHILDREN) {
916
- nextProp = null;
921
+ if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
922
+ DOMPropertyOperations.setValueForAttribute(
923
+ getNode(this),
924
+ propKey,
925
+ nextProp
926
+ );
927
}
918
- DOMPropertyOperations.setValueForAttribute(
919
- getNode(this),
920
- propKey,
921
- nextProp
922
- );
928
} else if (this._namespaceURI === DOMNamespaces.svg) {
924
- DOMPropertyOperations.setValueForSVGAttribute(
925
- getNode(this),
926
- propKey,
927
- nextProp
928
- );
929
+ if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
930
+ DOMPropertyOperations.setValueForSVGAttribute(
931
+ getNode(this),
932
+ propKey,
933
+ nextProp
934
+ );
935
+ }
936
} else if (
937
DOMProperty.properties[propKey] ||
938
DOMProperty.isCustomAttribute(propKey)) {
src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
+89
-5
@@ -244,16 +244,100 @@ describe('ReactDOMComponent', function() {
244
expect(stubStyle.display).toEqual('');
245
});
246
247
- it('should skip child object attribute on web components', function() {
247
+ it('should skip reserved props on web components', function() {
248
var container = document.createElement('div');
249
250
- // Test initial render to null
251
- ReactDOM.render(<my-component children={['foo']} />, container);
250
+ ReactDOM.render(
251
+ <my-component
252
+ children={['foo']}
253
+ suppressContentEditableWarning={true}
254
+ />,
255
+ container
256
+ );
257
expect(container.firstChild.hasAttribute('children')).toBe(false);
258
+ expect(
259
+ container.firstChild.hasAttribute('suppressContentEditableWarning')
260
+ ).toBe(false);
261
254
- // Test updates to null
255
- ReactDOM.render(<my-component children={['foo']} />, container);
262
+ ReactDOM.render(
263
+ <my-component
264
+ children={['bar']}
265
+ suppressContentEditableWarning={false}
266
+ />,
267
+ container
268
+ );
269
expect(container.firstChild.hasAttribute('children')).toBe(false);
270
+ expect(
271
+ container.firstChild.hasAttribute('suppressContentEditableWarning')
272
+ ).toBe(false);
273
+ });
274
+
275
+ it('should skip dangerouslySetInnerHTML on web components', function() {
276
+ var container = document.createElement('div');
277
+
278
+ ReactDOM.render(
279
+ <my-component dangerouslySetInnerHTML={{__html: 'hi'}} />,
280
+ container
281
+ );
282
+ expect(
283
+ container.firstChild.hasAttribute('dangerouslySetInnerHTML')
284
+ ).toBe(false);
285
+
286
+ ReactDOM.render(
287
+ <my-component dangerouslySetInnerHTML={{__html: 'bye'}} />,
288
+ container
289
+ );
290
+ expect(
291
+ container.firstChild.hasAttribute('dangerouslySetInnerHTML')
292
+ ).toBe(false);
293
+ });
294
+
295
+ it('should skip reserved props on SVG components', function() {
296
+ var container = document.createElement('div');
297
+
298
+ ReactDOM.render(
299
+ <svg
300
+ children={['foo']}
301
+ suppressContentEditableWarning={true}
302
+ />,
303
+ container
304
+ );
305
+ expect(container.firstChild.hasAttribute('children')).toBe(false);
306
+ expect(
307
+ container.firstChild.hasAttribute('suppressContentEditableWarning')
308
+ ).toBe(false);
309
+
310
+ ReactDOM.render(
311
+ <svg
312
+ children={['bar']}
313
+ suppressContentEditableWarning={false}
314
+ />,
315
+ container
316
+ );
317
+ expect(container.firstChild.hasAttribute('children')).toBe(false);
318
+ expect(
319
+ container.firstChild.hasAttribute('suppressContentEditableWarning')
320
+ ).toBe(false);
321
+ });
322
+
323
+ it('should skip dangerouslySetInnerHTML on SVG components', function() {
324
+ var container = document.createElement('div');
325
+
326
+ ReactDOM.render(
327
+ <svg dangerouslySetInnerHTML={{__html: 'hi'}} />,
328
+ container
329
+ );
330
+ expect(
331
+ container.firstChild.hasAttribute('dangerouslySetInnerHTML')
332
+ ).toBe(false);
333
+
334
+ ReactDOM.render(
335
+ <svg dangerouslySetInnerHTML={{__html: 'bye'}} />,
336
+ container
337
+ );
338
+ expect(
339
+ container.firstChild.hasAttribute('dangerouslySetInnerHTML')
340
+ ).toBe(false);
341
});
342
343
it('should remove attributes', function() {