Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ import {
enableScopeAPI,
enableTrustedTypesIntegration,
enableAsyncActions,
disableElementishSuppressionCheck,
} from 'shared/ReactFeatureFlags';
import {
HostComponent,
Expand Down Expand Up @@ -1528,13 +1529,32 @@ export function didNotMatchHydratedTextInstance(
isConcurrentMode: boolean,
shouldWarnDev: boolean,
) {
if (parentProps[SUPPRESS_HYDRATION_WARNING] !== true) {
checkForUnmatchedText(
textInstance.nodeValue,
text,
isConcurrentMode,
shouldWarnDev,
);
if (disableElementishSuppressionCheck) {
if (parentProps[SUPPRESS_HYDRATION_WARNING] !== true) {
checkForUnmatchedText(
textInstance.nodeValue,
text,
isConcurrentMode,
shouldWarnDev,
);
}
} else {
if (
parentProps[SUPPRESS_HYDRATION_WARNING] !== true &&
// TODO: remove this hack.
// For elementish text nodes, we need to check their prop through the parent.
parentProps.children &&
parentProps.children.length === 1 &&
parentProps.children.props &&
parentProps.children.props[SUPPRESS_HYDRATION_WARNING] !== true
) {
checkForUnmatchedText(
textInstance.nodeValue,
text,
isConcurrentMode,
shouldWarnDev,
);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ let Scheduler;
let React;
let ReactDOMClient;
let ReactDOMFizzServer;
let ReactFeatureFlags;
let document;
let writable;
let container;
Expand All @@ -33,6 +34,7 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
ReactDOMClient = require('react-dom/client');
ReactDOMFizzServer = require('react-dom/server');
Stream = require('stream');
ReactFeatureFlags = require('shared/ReactFeatureFlags');

const InternalTestUtils = require('internal-test-utils');
waitForAll = InternalTestUtils.waitForAll;
Expand Down Expand Up @@ -784,4 +786,55 @@ describe('ReactDOMFizzServerHydrationWarning', () => {
</div>,
);
});

// @gate enableClientRenderFallbackOnTextMismatch && !disableElementishSuppressionCheck
it('suppresses but does not fix text mismatches with suppressHydrationWarning for element-ish children', async () => {
function App({isClient}) {
// This is similar to <fbt>.
// We don't toString it because you must instead provide a value prop.
const obj = {
$$typeof: Symbol.for('react.element'),
type: props => props.content,
ref: null,
key: null,
props: {
suppressHydrationWarning: true,
content: isClient ? 'Client Text' : 'Server Text',
},
toString() {
return this.props.content;
},
};

return (
<div>
<span>{obj}</span>
</div>
);
}
await act(() => {
const {pipe} = ReactDOMFizzServer.renderToPipeableStream(
<App isClient={false} />,
);
pipe(writable);
});
expect(getVisibleChildren(container)).toEqual(
<div>
<span>Server Text</span>
</div>,
);
ReactDOMClient.hydrateRoot(container, <App isClient={true} />, {
onRecoverableError(error) {
// Don't miss a hydration error. There should be none.
Scheduler.log(error.message);
},
});
await waitForAll([]);
// The text mismatch should be *silently* fixed. Even in production.
expect(getVisibleChildren(container)).toEqual(
<div>
<span>Server Text</span>
</div>,
);
});
});
2 changes: 2 additions & 0 deletions packages/shared/ReactFeatureFlags.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export const disableSchedulerTimeoutInWorkLoop = false;
// those can be fixed.
export const enableDeferRootSchedulingToMicrotask = true;

export const disableElementishSuppressionCheck = true;

// -----------------------------------------------------------------------------
// Slated for removal in the future (significant effort)
//
Expand Down
3 changes: 2 additions & 1 deletion packages/shared/forks/ReactFeatureFlags.native-fb.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import typeof * as DynamicExportsType from './ReactFeatureFlags.native-fb-dynami
// Re-export dynamic flags from the internal module.
// Intentionally using * because this import is compiled to a `require` call.
import * as dynamicFlagsUntyped from 'ReactNativeInternalFeatureFlags';
import {disableElementishSuppressionCheck} from 'shared/ReactFeatureFlags';
const dynamicFlags: DynamicExportsType = (dynamicFlagsUntyped: any);

// We destructure each value before re-exporting to avoid a dynamic look-up on
Expand Down Expand Up @@ -93,7 +94,7 @@ export const disableClientCache = true;

export const enableServerComponentKeys = true;
export const enableServerComponentLogs = true;

export const disableElementishSuppressionCheck = true;
// TODO: Roll out with GK. Don't keep as dynamic flag for too long, though,
// because JSX is an extremely hot path.
export const enableRefAsProp = false;
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.native-oss.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export const enableNewBooleanProps = true;
export const enableTransitionTracing = false;
export const enableDO_NOT_USE_disableStrictPassiveEffect = false;
export const passChildrenWhenCloningPersistedNodes = false;
export const disableElementishSuppressionCheck = true;

// Profiling Only
export const enableProfilerTimer = __PROFILE__;
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.test-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export const disableClientCache = true;
export const enableServerComponentKeys = true;
export const enableServerComponentLogs = true;
export const enableInfiniteRenderLoopDetection = false;
export const disableElementishSuppressionCheck = true;

// TODO: This must be in sync with the main ReactFeatureFlags file because
// the Test Renderer's value must be the same as the one used by the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export const enableReactTestRendererWarning = false;
export const disableLegacyMode = false;

export const enableBigIntSupport = false;
export const disableElementishSuppressionCheck = true;

// Flow magic to verify the exports of this file match the original version.
((((null: any): ExportsType): FeatureFlagsType): ExportsType);
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export const enableReactTestRendererWarning = false;
export const disableLegacyMode = false;

export const enableBigIntSupport = true;
export const disableElementishSuppressionCheck = true;

// Flow magic to verify the exports of this file match the original version.
((((null: any): ExportsType): FeatureFlagsType): ExportsType);
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.www-dynamic.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const enableRefAsProp = __VARIANT__;
export const enableClientRenderFallbackOnTextMismatch = __VARIANT__;
export const enableNewBooleanProps = __VARIANT__;
export const enableRetryLaneExpiration = __VARIANT__;
export const disableElementishSuppressionCheck = !__VARIANT__;
export const retryLaneExpirationMs = 5000;
export const syncLaneExpirationMs = 250;
export const transitionLaneExpirationMs = 5000;
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.www.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const {
enableRefAsProp,
enableNewBooleanProps,
enableClientRenderFallbackOnTextMismatch,
disableElementishSuppressionCheck,
} = dynamicFeatureFlags;

// On WWW, __EXPERIMENTAL__ is used for a new modern build.
Expand Down