Skip to content

Commit ffb6c6c

Browse files
authored
fix: skip dangerouslySetInnerHtml hydration warning if it's undefined (facebook#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
1 parent 1078029 commit ffb6c6c

File tree

2 files changed

+58
-6
lines changed

2 files changed

+58
-6
lines changed

packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,4 +548,57 @@ describe('ReactDOMServerHydration', () => {
548548
expect(ref.current).toBe(div);
549549
expect(element.innerHTML).toBe('<div>Hello World</div>');
550550
});
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+
});
551604
});

packages/react-dom/src/client/ReactDOMComponent.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,12 +1110,11 @@ export function diffHydratedProperties(
11101110
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
11111111
const serverHTML = domElement.innerHTML;
11121112
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+
}
11191118
}
11201119
} else if (propKey === STYLE) {
11211120
// $FlowFixMe - Should be inferred as not undefined.

0 commit comments

Comments
 (0)