Fix suppressHydrationWarning not working in production (#24271)

This commit is contained in:
dan 2022-04-04 16:23:58 +01:00 committed by GitHub
parent 985272e268
commit fc47cb1b61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 101 additions and 11 deletions

View File

@ -2811,4 +2811,96 @@ describe('ReactDOMFizzServer', () => {
</ul>,
);
});
// @gate experimental
it('suppresses and fixes text mismatches with suppressHydrationWarning', async () => {
function App({isClient}) {
return (
<div>
<span
suppressHydrationWarning={true}
data-attr={isClient ? 'client-attr' : 'server-attr'}>
{isClient ? 'Client Text' : 'Server Text'}
</span>
<span suppressHydrationWarning={true}>{isClient ? 2 : 1}</span>
<span suppressHydrationWarning={true}>
hello,{isClient ? 'client' : 'server'}
</span>
</div>
);
}
await act(async () => {
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
<App isClient={false} />,
);
pipe(writable);
});
expect(getVisibleChildren(container)).toEqual(
<div>
<span data-attr="server-attr">Server Text</span>
<span>1</span>
<span>
{'hello,'}
{'server'}
</span>
</div>,
);
ReactDOMClient.hydrateRoot(container, <App isClient={true} />, {
onRecoverableError(error) {
// Don't miss a hydration error. There should be none.
Scheduler.unstable_yieldValue(error.message);
},
});
expect(Scheduler).toFlushAndYield([]);
// The text mismatch should be *silently* fixed. Even in production.
// The attribute mismatch should be ignored and not fixed.
expect(getVisibleChildren(container)).toEqual(
<div>
<span data-attr="server-attr">Client Text</span>
<span>2</span>
<span>
{'hello,'}
{'client'}
</span>
</div>,
);
});
// @gate experimental
it('suppresses and does not fix html mismatches with suppressHydrationWarning', async () => {
function App({isClient}) {
return (
<div>
<p
suppressHydrationWarning={true}
dangerouslySetInnerHTML={{
__html: isClient ? 'Client HTML' : 'Server HTML',
}}
/>
</div>
);
}
await act(async () => {
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
<App isClient={false} />,
);
pipe(writable);
});
expect(getVisibleChildren(container)).toEqual(
<div>
<p>Server HTML</p>
</div>,
);
ReactDOMClient.hydrateRoot(container, <App isClient={true} />, {
onRecoverableError(error) {
Scheduler.unstable_yieldValue(error.message);
},
});
expect(Scheduler).toFlushAndYield([]);
expect(getVisibleChildren(container)).toEqual(
<div>
<p>Server HTML</p>
</div>,
);
});
});

View File

@ -91,7 +91,6 @@ const STYLE = 'style';
const HTML = '__html';
let warnedUnknownTags;
let suppressHydrationWarning;
let validatePropertiesInDevelopment;
let warnForPropDifference;
@ -875,7 +874,6 @@ export function diffHydratedProperties(
let extraAttributeNames: Set<string>;
if (__DEV__) {
suppressHydrationWarning = rawProps[SUPPRESS_HYDRATION_WARNING] === true;
isCustomComponentTag = isCustomComponent(tag, rawProps);
validatePropertiesInDevelopment(tag, rawProps);
}
@ -984,7 +982,7 @@ export function diffHydratedProperties(
// TODO: Should we use domElement.firstChild.nodeValue to compare?
if (typeof nextProp === 'string') {
if (domElement.textContent !== nextProp) {
if (!suppressHydrationWarning) {
if (rawProps[SUPPRESS_HYDRATION_WARNING] !== true) {
checkForUnmatchedText(
domElement.textContent,
nextProp,
@ -996,7 +994,7 @@ export function diffHydratedProperties(
}
} else if (typeof nextProp === 'number') {
if (domElement.textContent !== '' + nextProp) {
if (!suppressHydrationWarning) {
if (rawProps[SUPPRESS_HYDRATION_WARNING] !== true) {
checkForUnmatchedText(
domElement.textContent,
nextProp,
@ -1028,7 +1026,7 @@ export function diffHydratedProperties(
isCustomComponentTag && enableCustomElementPropertySupport
? null
: getPropertyInfo(propKey);
if (suppressHydrationWarning) {
if (rawProps[SUPPRESS_HYDRATION_WARNING] === true) {
// Don't bother comparing. We're ignoring all these warnings.
} else if (
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
@ -1150,8 +1148,11 @@ export function diffHydratedProperties(
if (__DEV__) {
if (shouldWarnDev) {
// $FlowFixMe - Should be inferred as not undefined.
if (extraAttributeNames.size > 0 && !suppressHydrationWarning) {
if (
// $FlowFixMe - Should be inferred as not undefined.
extraAttributeNames.size > 0 &&
rawProps[SUPPRESS_HYDRATION_WARNING] !== true
) {
// $FlowFixMe - Should be inferred as not undefined.
warnForExtraAttributes(extraAttributeNames);
}

View File

@ -132,10 +132,7 @@ type SelectionInformation = {|
selectionRange: mixed,
|};
let SUPPRESS_HYDRATION_WARNING;
if (__DEV__) {
SUPPRESS_HYDRATION_WARNING = 'suppressHydrationWarning';
}
const SUPPRESS_HYDRATION_WARNING = 'suppressHydrationWarning';
const SUSPENSE_START_DATA = '$';
const SUSPENSE_END_DATA = '/$';