fix: skip dangerouslySetInnerHtml hydration warning if it's undefined (#18676)
* test: Add failing case for dangerouslySetInnerHtml=undefined * fix: skip dangerouslySetInnerHtml warning if it's undefined * test: add similar test that should trigger the warning * chore: Remove redundant nullish check * Poke yarn_test_www_variant which timed out * test: Add smaller test for innerHTML=string to innerHTML=undefined
Sebastian Silbermann committed
Apr 20, 2020 at 19:46 UTC
ffb6c6c07b1a6dcabd04b22a6a5afeab96d53ae2
2 files changed
+58
-6
packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js
+53
@@ -548,4 +548,57 @@ describe('ReactDOMServerHydration', () => {
548
expect(ref.current).toBe(div);
549
expect(element.innerHTML).toBe('<div>Hello World</div>');
550
});
551
+
552
+ // regression test for https://github.com/facebook/react/issues/17170
553
+ it('should not warn if dangerouslySetInnerHtml=undefined', () => {
554
+ const domElement = document.createElement('div');
555
+ const reactElement = (
556
+ <div dangerouslySetInnerHTML={undefined}>
557
+ <p>Hello, World!</p>
558
+ </div>
559
+ );
560
+ const markup = ReactDOMServer.renderToStaticMarkup(reactElement);
561
+ domElement.innerHTML = markup;
562
+
563
+ ReactDOM.hydrate(reactElement, domElement);
564
+
565
+ expect(domElement.innerHTML).toEqual(markup);
566
+ });
567
+
568
+ it('should warn if innerHTML mismatches with dangerouslySetInnerHTML=undefined and children on the client', () => {
569
+ const domElement = document.createElement('div');
570
+ const markup = ReactDOMServer.renderToStaticMarkup(
571
+ <div dangerouslySetInnerHTML={{__html: '<p>server</p>'}} />,
572
+ );
573
+ domElement.innerHTML = markup;
574
+
575
+ expect(() => {
576
+ ReactDOM.hydrate(
577
+ <div dangerouslySetInnerHTML={undefined}>
578
+ <p>client</p>
579
+ </div>,
580
+ domElement,
581
+ );
582
+
583
+ expect(domElement.innerHTML).not.toEqual(markup);
584
+ }).toErrorDev(
585
+ 'Warning: Text content did not match. Server: "server" Client: "client"',
586
+ );
587
+ });
588
+
589
+ it('should warn if innerHTML mismatches with dangerouslySetInnerHTML=undefined on the client', () => {
590
+ const domElement = document.createElement('div');
591
+ const markup = ReactDOMServer.renderToStaticMarkup(
592
+ <div dangerouslySetInnerHTML={{__html: '<p>server</p>'}} />,
593
+ );
594
+ domElement.innerHTML = markup;
595
+
596
+ expect(() => {
597
+ ReactDOM.hydrate(<div dangerouslySetInnerHTML={undefined} />, domElement);
598
+
599
+ expect(domElement.innerHTML).not.toEqual(markup);
600
+ }).toErrorDev(
601
+ 'Warning: Did not expect server HTML to contain a <p> in <div>',
602
+ );
603
+ });
604
});
packages/react-dom/src/client/ReactDOMComponent.js
+5
-6
@@ -1110,12 +1110,11 @@ export function diffHydratedProperties(
1110
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
1111
const serverHTML = domElement.innerHTML;
1112
const nextHtml = nextProp ? nextProp[HTML] : undefined;
1113
- const expectedHTML = normalizeHTML(
1114
- domElement,
1115
- nextHtml != null ? nextHtml : '',
1116
- );
1117
- if (expectedHTML !== serverHTML) {
1118
- warnForPropDifference(propKey, serverHTML, expectedHTML);
1113
+ if (nextHtml != null) {
1114
+ const expectedHTML = normalizeHTML(domElement, nextHtml);
1115
+ if (expectedHTML !== serverHTML) {
1116
+ warnForPropDifference(propKey, serverHTML, expectedHTML);
1117
+ }
1118
}
1119
} else if (propKey === STYLE) {
1120
// $FlowFixMe - Should be inferred as not undefined.