Dedupe unknown tag name warning and ignore <time> (#10275)
* Deduplicate unknown DOM tag warning * Don't warn about <time> because it is widely used Other browsers implement it, and Chrome will ship it soon too. * Use hasOwnProperty * Fix corner case: hasOwnProperty as a tag * Update comments to be more correct factually
Dan Abramov committed
Jul 26, 2017 at 11:57 UTC
dea43046ef75064279bc833149400beca500b825
3 files changed
+75
-21
src/renderers/dom/fiber/ReactDOMFiberComponent.js
+23
-9
@@ -65,6 +65,14 @@ var {
65
} = DOMNamespaces;
66
67
if (__DEV__) {
68
+ var warnedUnknownTags = {
69
+ // Chrome is the only major browser not shipping <time>. But as of July
70
+ // 2017 it intends to ship it due to widespread usage. We intentionally
71
+ // *don't* warn for <time> even if it's unrecognized by Chrome because
72
+ // it soon will be, and many apps have been using it anyway.
73
+ time: true,
74
+ };
75
+
76
var validatePropertiesInDevelopment = function(type, props) {
77
validateARIAProperties(type, props);
78
validateInputPropertes(type, props);
@@ -414,15 +422,21 @@ var ReactDOMFiberComponent = {
422
423
if (__DEV__) {
424
if (namespaceURI === HTML_NAMESPACE) {
417
- warning(
418
- isCustomComponentTag ||
419
- Object.prototype.toString.call(domElement) !==
420
- '[object HTMLUnknownElement]',
421
- 'The tag <%s> is unrecognized in this browser. ' +
422
- 'If you meant to render a React component, start its name with ' +
423
- 'an uppercase letter.',
424
- type,
425
- );
425
+ if (
426
+ !isCustomComponentTag &&
427
+ Object.prototype.toString.call(domElement) ===
428
+ '[object HTMLUnknownElement]' &&
429
+ !Object.prototype.hasOwnProperty.call(warnedUnknownTags, type)
430
+ ) {
431
+ warnedUnknownTags[type] = true;
432
+ warning(
433
+ false,
434
+ 'The tag <%s> is unrecognized in this browser. ' +
435
+ 'If you meant to render a React component, start its name with ' +
436
+ 'an uppercase letter.',
437
+ type,
438
+ );
439
+ }
440
}
441
}
442
src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
+30
-3
@@ -822,17 +822,44 @@ describe('ReactDOMComponent', () => {
822
if (this instanceof window.HTMLUnknownElement) {
823
return '[object HTMLUnknownElement]';
824
}
825
+ // Special case! Read explanation below in the test.
826
+ if (this instanceof window.HTMLTimeElement) {
827
+ return '[object HTMLUnknownElement]';
828
+ }
829
return realToString.apply(this, arguments);
830
};
831
Object.prototype.toString = wrappedToString; // eslint-disable-line no-extend-native
828
- ReactTestUtils.renderIntoDocument(<mycustomcomponent />);
832
+
833
+ ReactTestUtils.renderIntoDocument(<bar />);
834
+ // Test deduplication
835
+ ReactTestUtils.renderIntoDocument(<foo />);
836
+ ReactTestUtils.renderIntoDocument(<foo />);
837
+ // This is a funny case.
838
+ // Chrome is the only major browser not shipping <time>. But as of July
839
+ // 2017 it intends to ship it due to widespread usage. We intentionally
840
+ // *don't* warn for <time> even if it's unrecognized by Chrome because
841
+ // it soon will be, and many apps have been using it anyway.
842
+ ReactTestUtils.renderIntoDocument(<time />);
843
+ // Corner case. Make sure out deduplication logic doesn't break with weird tag.
844
+ ReactTestUtils.renderIntoDocument(<hasOwnProperty />);
845
} finally {
846
Object.prototype.toString = realToString; // eslint-disable-line no-extend-native
847
}
848
833
- expectDev(console.error.calls.count()).toBe(1);
849
+ expectDev(console.error.calls.count()).toBe(4);
850
expectDev(console.error.calls.argsFor(0)[0]).toContain(
835
- 'The tag <mycustomcomponent> is unrecognized in this browser',
851
+ 'The tag <bar> is unrecognized in this browser',
852
+ );
853
+ expectDev(console.error.calls.argsFor(1)[0]).toContain(
854
+ 'The tag <foo> is unrecognized in this browser',
855
+ );
856
+ expectDev(console.error.calls.argsFor(2)[0]).toContain(
857
+ '<hasOwnProperty /> is using uppercase HTML',
858
+ );
859
+ expectDev(console.error.calls.argsFor(3)[0]).toContain(
860
+ ReactDOMFeatureFlags.useFiber
861
+ ? 'The tag <hasOwnProperty> is unrecognized in this browser'
862
+ : 'The tag <hasownproperty> is unrecognized in this browser',
863
);
864
});
865
src/renderers/dom/stack/client/ReactDOMComponent.js
+22
-9
@@ -374,6 +374,13 @@ function validateDangerousTag(tag) {
374
}
375
376
var globalIdCounter = 1;
377
+var warnedUnknownTags = {
378
+ // Chrome is the only major browser not shipping <time>. But as of July
379
+ // 2017 it intends to ship it due to widespread usage. We intentionally
380
+ // *don't* warn for <time> even if it's unrecognized by Chrome because
381
+ // it soon will be, and many apps have been using it anyway.
382
+ time: true,
383
+};
384
385
/**
386
* Creates a new React class that is idempotent and capable of containing other
@@ -578,15 +585,21 @@ ReactDOMComponent.Mixin = {
585
didWarnShadyDOM = true;
586
}
587
if (this._namespaceURI === DOMNamespaces.html) {
581
- warning(
582
- isCustomComponentTag ||
583
- Object.prototype.toString.call(el) !==
584
- '[object HTMLUnknownElement]',
585
- 'The tag <%s> is unrecognized in this browser. ' +
586
- 'If you meant to render a React component, start its name with ' +
587
- 'an uppercase letter.',
588
- this._tag,
589
- );
588
+ if (
589
+ !isCustomComponentTag &&
590
+ Object.prototype.toString.call(el) ===
591
+ '[object HTMLUnknownElement]' &&
592
+ !Object.prototype.hasOwnProperty.call(warnedUnknownTags, this._tag)
593
+ ) {
594
+ warnedUnknownTags[this._tag] = true;
595
+ warning(
596
+ false,
597
+ 'The tag <%s> is unrecognized in this browser. ' +
598
+ 'If you meant to render a React component, start its name with ' +
599
+ 'an uppercase letter.',
600
+ this._tag,
601
+ );
602
+ }
603
}
604
}
605
ReactDOMComponentTree.precacheNode(this, el);