From 5eab1bbe29860e3bc262a7747aead016482b4999 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Wed, 2 Mar 2016 01:57:48 +0000 Subject: [PATCH] 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. --- src/renderers/dom/shared/ReactDOMComponent.js | 37 +++++--- .../__tests__/ReactDOMComponent-test.js | 94 ++++++++++++++++++- 2 files changed, 111 insertions(+), 20 deletions(-) diff --git a/src/renderers/dom/shared/ReactDOMComponent.js b/src/renderers/dom/shared/ReactDOMComponent.js index 82fef299d5f07..ec1a0f4ab5f83 100644 --- a/src/renderers/dom/shared/ReactDOMComponent.js +++ b/src/renderers/dom/shared/ReactDOMComponent.js @@ -53,9 +53,13 @@ var registrationNameModules = EventPluginRegistry.registrationNameModules; // For quickly matching children type, to test if can be treated as content. var CONTENT_TYPES = {'string': true, 'number': true}; -var CHILDREN = keyOf({children: null}); var STYLE = keyOf({style: null}); var HTML = keyOf({__html: null}); +var RESERVED_PROPS = { + children: null, + dangerouslySetInnerHTML: null, + suppressContentEditableWarning: null, +}; function getDeclarationErrorAddendum(internalInstance) { if (internalInstance) { @@ -633,11 +637,13 @@ ReactDOMComponent.Mixin = { } var markup = null; if (this._tag != null && isCustomComponent(this._tag, props)) { - if (propKey !== CHILDREN) { + if (!RESERVED_PROPS.hasOwnProperty(propKey)) { markup = DOMPropertyOperations.createMarkupForCustomAttribute(propKey, propValue); } } else if (this._namespaceURI === DOMNamespaces.svg) { - markup = DOMPropertyOperations.createMarkupForSVGAttribute(propKey, propValue); + if (!RESERVED_PROPS.hasOwnProperty(propKey)) { + markup = DOMPropertyOperations.createMarkupForSVGAttribute(propKey, propValue); + } } else { markup = DOMPropertyOperations.createMarkupForProperty(propKey, propValue); } @@ -912,20 +918,21 @@ ReactDOMComponent.Mixin = { deleteListener(this, propKey); } } else if (isCustomComponent(this._tag, nextProps)) { - if (propKey === CHILDREN) { - nextProp = null; + if (!RESERVED_PROPS.hasOwnProperty(propKey)) { + DOMPropertyOperations.setValueForAttribute( + getNode(this), + propKey, + nextProp + ); } - DOMPropertyOperations.setValueForAttribute( - getNode(this), - propKey, - nextProp - ); } else if (this._namespaceURI === DOMNamespaces.svg) { - DOMPropertyOperations.setValueForSVGAttribute( - getNode(this), - propKey, - nextProp - ); + if (!RESERVED_PROPS.hasOwnProperty(propKey)) { + DOMPropertyOperations.setValueForSVGAttribute( + getNode(this), + propKey, + nextProp + ); + } } else if ( DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) { diff --git a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js index 3bae74a04b3da..bc2fbc6563556 100644 --- a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js +++ b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js @@ -244,16 +244,100 @@ describe('ReactDOMComponent', function() { expect(stubStyle.display).toEqual(''); }); - it('should skip child object attribute on web components', function() { + it('should skip reserved props on web components', function() { var container = document.createElement('div'); - // Test initial render to null - ReactDOM.render(, container); + ReactDOM.render( + , + container + ); expect(container.firstChild.hasAttribute('children')).toBe(false); + expect( + container.firstChild.hasAttribute('suppressContentEditableWarning') + ).toBe(false); - // Test updates to null - ReactDOM.render(, container); + ReactDOM.render( + , + container + ); expect(container.firstChild.hasAttribute('children')).toBe(false); + expect( + container.firstChild.hasAttribute('suppressContentEditableWarning') + ).toBe(false); + }); + + it('should skip dangerouslySetInnerHTML on web components', function() { + var container = document.createElement('div'); + + ReactDOM.render( + , + container + ); + expect( + container.firstChild.hasAttribute('dangerouslySetInnerHTML') + ).toBe(false); + + ReactDOM.render( + , + container + ); + expect( + container.firstChild.hasAttribute('dangerouslySetInnerHTML') + ).toBe(false); + }); + + it('should skip reserved props on SVG components', function() { + var container = document.createElement('div'); + + ReactDOM.render( + , + container + ); + expect(container.firstChild.hasAttribute('children')).toBe(false); + expect( + container.firstChild.hasAttribute('suppressContentEditableWarning') + ).toBe(false); + + ReactDOM.render( + , + container + ); + expect(container.firstChild.hasAttribute('children')).toBe(false); + expect( + container.firstChild.hasAttribute('suppressContentEditableWarning') + ).toBe(false); + }); + + it('should skip dangerouslySetInnerHTML on SVG components', function() { + var container = document.createElement('div'); + + ReactDOM.render( + , + container + ); + expect( + container.firstChild.hasAttribute('dangerouslySetInnerHTML') + ).toBe(false); + + ReactDOM.render( + , + container + ); + expect( + container.firstChild.hasAttribute('dangerouslySetInnerHTML') + ).toBe(false); }); it('should remove attributes', function() {