Skip to content

Commit

Permalink
Move text mismatch throwing to the hydration context too
Browse files Browse the repository at this point in the history
  • Loading branch information
sebmarkbage committed Mar 5, 2024
1 parent 89ac64c commit 767592f
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 19 deletions.
31 changes: 17 additions & 14 deletions packages/react-dom-bindings/src/client/ReactDOMComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -324,12 +324,9 @@ function checkForUnmatchedText(
const normalizedClientText = normalizeMarkupForTextOrAttribute(clientText);
const normalizedServerText = normalizeMarkupForTextOrAttribute(serverText);
if (normalizedServerText === normalizedClientText) {
return;
return true;
}

// In concurrent roots, we throw when there's a text mismatch and revert to
// client rendering, up to the nearest Suspense boundary.
throw new Error('Text content does not match server-rendered HTML.');
return false;
}

function noop() {}
Expand Down Expand Up @@ -2823,7 +2820,7 @@ export function hydrateProperties(
tag: string,
props: Object,
hostContext: HostContext,
): void {
): boolean {
if (__DEV__) {
validatePropertiesInDevelopment(tag, props);
}
Expand Down Expand Up @@ -2936,11 +2933,13 @@ export function hydrateProperties(
typeof children === 'number' ||
(enableBigIntSupport && typeof children === 'bigint')
) {
// $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint
if (domElement.textContent !== '' + children) {
if (props.suppressHydrationWarning !== true) {
checkForUnmatchedText(domElement.textContent, children);
}
if (
// $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint
domElement.textContent !== '' + children &&
props.suppressHydrationWarning !== true &&
!checkForUnmatchedText(domElement.textContent, children)
) {
return false;
}
}

Expand All @@ -2956,6 +2955,8 @@ export function hydrateProperties(
// TODO: This cast may not be sound for SVG, MathML or custom elements.
trapClickOnNonInteractiveElement(((domElement: any): HTMLElement));
}

return true;
}

export function diffHydratedProperties(
Expand Down Expand Up @@ -3018,14 +3019,16 @@ export function hydrateText(
textNode: Text,
text: string,
parentProps: null | Object,
): void {
): boolean {
const isDifferent = textNode.nodeValue !== text;
if (
isDifferent &&
(parentProps === null || parentProps.suppressHydrationWarning !== true)
(parentProps === null || parentProps.suppressHydrationWarning !== true) &&
!checkForUnmatchedText(textNode.nodeValue, text)
) {
checkForUnmatchedText(textNode.nodeValue, text);
return false;
}
return true;
}

export function diffHydratedText(textNode: Text, text: string): null | string {
Expand Down
6 changes: 3 additions & 3 deletions packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -1391,13 +1391,13 @@ export function hydrateInstance(
props: Props,
hostContext: HostContext,
internalInstanceHandle: Object,
): void {
): boolean {
precacheFiberNode(internalInstanceHandle, instance);
// TODO: Possibly defer this until the commit phase where all the events
// get attached.
updateFiberProps(instance, props);

hydrateProperties(instance, type, props, hostContext);
return hydrateProperties(instance, type, props, hostContext);
}

// Returns a Map of properties that were different on the server.
Expand Down Expand Up @@ -1429,7 +1429,7 @@ export function hydrateTextInstance(
text: string,
internalInstanceHandle: Object,
parentInstanceProps: null | Props,
): void {
): boolean {
precacheFiberNode(internalInstanceHandle, textInstance);

return hydrateText(textInstance, text, parentInstanceProps);
Expand Down
15 changes: 13 additions & 2 deletions packages/react-reconciler/src/ReactFiberHydrationContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -566,13 +566,16 @@ function prepareToHydrateHostInstance(
}
}

hydrateInstance(
const didHydrate = hydrateInstance(
instance,
fiber.type,
fiber.memoizedProps,
hostContext,
fiber,
);
if (!didHydrate) {
throw new Error('Text content does not match server-rendered HTML.');
}
}

function prepareToHydrateHostTextInstance(fiber: Fiber): void {
Expand Down Expand Up @@ -638,7 +641,15 @@ function prepareToHydrateHostTextInstance(fiber: Fiber): void {
// TODO: What if it's a SuspenseInstance?
}

hydrateTextInstance(textInstance, textContent, fiber, parentProps);
const didHydrate = hydrateTextInstance(
textInstance,
textContent,
fiber,
parentProps,
);
if (!didHydrate) {
throw new Error('Text content does not match server-rendered HTML.');
}
}

function prepareToHydrateHostSuspenseInstance(fiber: Fiber): void {
Expand Down

0 comments on commit 767592f

Please sign in to comment.