From ffb6c6c07b1a6dcabd04b22a6a5afeab96d53ae2 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Mon, 20 Apr 2020 19:46:55 +0200 Subject: [PATCH] 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 --- .../ReactServerRenderingHydration-test.js | 53 +++++++++++++++++++ .../react-dom/src/client/ReactDOMComponent.js | 11 ++-- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js b/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js index 14dbe62d3996..770740e59102 100644 --- a/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js +++ b/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js @@ -548,4 +548,57 @@ describe('ReactDOMServerHydration', () => { expect(ref.current).toBe(div); expect(element.innerHTML).toBe('
Hello World
'); }); + + // regression test for https://github.com/facebook/react/issues/17170 + it('should not warn if dangerouslySetInnerHtml=undefined', () => { + const domElement = document.createElement('div'); + const reactElement = ( +
+

Hello, World!

+
+ ); + const markup = ReactDOMServer.renderToStaticMarkup(reactElement); + domElement.innerHTML = markup; + + ReactDOM.hydrate(reactElement, domElement); + + expect(domElement.innerHTML).toEqual(markup); + }); + + it('should warn if innerHTML mismatches with dangerouslySetInnerHTML=undefined and children on the client', () => { + const domElement = document.createElement('div'); + const markup = ReactDOMServer.renderToStaticMarkup( +
server

'}} />, + ); + domElement.innerHTML = markup; + + expect(() => { + ReactDOM.hydrate( +
+

client

+
, + domElement, + ); + + expect(domElement.innerHTML).not.toEqual(markup); + }).toErrorDev( + 'Warning: Text content did not match. Server: "server" Client: "client"', + ); + }); + + it('should warn if innerHTML mismatches with dangerouslySetInnerHTML=undefined on the client', () => { + const domElement = document.createElement('div'); + const markup = ReactDOMServer.renderToStaticMarkup( +
server

'}} />, + ); + domElement.innerHTML = markup; + + expect(() => { + ReactDOM.hydrate(
, domElement); + + expect(domElement.innerHTML).not.toEqual(markup); + }).toErrorDev( + 'Warning: Did not expect server HTML to contain a

in

', + ); + }); }); diff --git a/packages/react-dom/src/client/ReactDOMComponent.js b/packages/react-dom/src/client/ReactDOMComponent.js index a75cb9799587..1517264cb895 100644 --- a/packages/react-dom/src/client/ReactDOMComponent.js +++ b/packages/react-dom/src/client/ReactDOMComponent.js @@ -1110,12 +1110,11 @@ export function diffHydratedProperties( } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { const serverHTML = domElement.innerHTML; const nextHtml = nextProp ? nextProp[HTML] : undefined; - const expectedHTML = normalizeHTML( - domElement, - nextHtml != null ? nextHtml : '', - ); - if (expectedHTML !== serverHTML) { - warnForPropDifference(propKey, serverHTML, expectedHTML); + if (nextHtml != null) { + const expectedHTML = normalizeHTML(domElement, nextHtml); + if (expectedHTML !== serverHTML) { + warnForPropDifference(propKey, serverHTML, expectedHTML); + } } } else if (propKey === STYLE) { // $FlowFixMe - Should be inferred as not undefined.