@samitouri / QOS-React-2 / commits / 5eab1bbe29

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() {