Skip to content

Commit 4b1a413

Browse files
committed
Make IE 11 not complain about non-crucial style attribute hydration mismatch
IE 11 parses & normalizes the style attribute as opposed to other browsers. The normalization added in this commit normalizes spacing which resolves most irrelevant style prop warnings, though a warning will still happen if the style attribute contains invalid CSS declarations. Fixes #11807
1 parent 8a1e396 commit 4b1a413

File tree

2 files changed

+55
-2
lines changed

2 files changed

+55
-2
lines changed

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,45 @@ describe('ReactDOMServerHydration', () => {
258258
expect(element.firstChild.focus).not.toHaveBeenCalled();
259259
});
260260

261+
it('should warn when the style property differs', () => {
262+
const element = document.createElement('div');
263+
element.innerHTML = ReactDOMServer.renderToString(
264+
<div style={{textDecoration: 'none', color: 'black'}} />,
265+
);
266+
expect(element.firstChild.style.textDecoration).toBe('none');
267+
expect(element.firstChild.style.color).toBe('black');
268+
269+
expect(() =>
270+
ReactDOM.hydrate(
271+
<div style={{textDecoration: 'none', color: 'white'}} />,
272+
element,
273+
),
274+
).toWarnDev(
275+
'Warning: Prop `style` did not match. Server: ' +
276+
'"text-decoration:none;color:black" Client: ' +
277+
'"text-decoration:none;color:white"',
278+
{withoutStack: true},
279+
);
280+
});
281+
282+
it('should not warn when the style property differs on whitespace only', () => {
283+
const element = document.createElement('div');
284+
element.innerHTML = ReactDOMServer.renderToString(
285+
<div style={{textDecoration: 'none', color: 'black'}} />,
286+
);
287+
expect(element.firstChild.style.textDecoration).toBe('none');
288+
expect(element.firstChild.style.color).toBe('black');
289+
290+
spyOnDevAndProd(console, 'error');
291+
292+
ReactDOM.hydrate(
293+
<div style={{textDecoration: 'none', color: 'black'}} />,
294+
element,
295+
);
296+
297+
expect(console.error).not.toHaveBeenCalled();
298+
});
299+
261300
it('should throw rendering portals on the server', () => {
262301
const div = document.createElement('div');
263302
expect(() => {

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,24 @@ if (__DEV__) {
102102
const NORMALIZE_NEWLINES_REGEX = /\r\n?/g;
103103
const NORMALIZE_NULL_AND_REPLACEMENT_REGEX = /\u0000|\uFFFD/g;
104104

105-
normalizeMarkupForTextOrAttribute = function(markup: mixed): string {
105+
normalizeMarkupForTextOrAttribute = function(
106+
markup: mixed,
107+
propName?: string,
108+
): string {
106109
const markupString =
107110
typeof markup === 'string' ? markup : '' + (markup: any);
108-
return markupString
111+
const markupNormalized = markupString
109112
.replace(NORMALIZE_NEWLINES_REGEX, '\n')
110113
.replace(NORMALIZE_NULL_AND_REPLACEMENT_REGEX, '');
114+
if (propName !== 'style') {
115+
return markupNormalized;
116+
}
117+
// IE 11 parses & normalizes the style attribute as opposed to other
118+
// browsers. The following normalization will still fail if the style
119+
// attribute contains invalid CSS declarations but the majority of
120+
// false warnings comes from spacing issues.
121+
// See https://github.com/facebook/react/issues/11807
122+
return markupNormalized.replace(/\s*([:;])\s*/, '$1').replace(/;$/, '');
111123
};
112124

113125
warnForTextDifference = function(
@@ -141,9 +153,11 @@ if (__DEV__) {
141153
}
142154
const normalizedClientValue = normalizeMarkupForTextOrAttribute(
143155
clientValue,
156+
propName,
144157
);
145158
const normalizedServerValue = normalizeMarkupForTextOrAttribute(
146159
serverValue,
160+
propName,
147161
);
148162
if (normalizedServerValue === normalizedClientValue) {
149163
return;

0 commit comments

Comments
 (0)