Skip to content

Commit 07a411b

Browse files
committed
Handle hydration errors in React 18
This reverts commit 6dfa1c5.
1 parent c31004a commit 07a411b

File tree

3 files changed

+690
-282
lines changed

3 files changed

+690
-282
lines changed

packages/next/src/client/components/react-dev-overlay/internal/container/RuntimeError/component-stack-pseudo-html.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export function PseudoHtmlDiff({
6666
firstContent: string
6767
secondContent: string
6868
reactOutputComponentDiff: string | undefined
69-
hydrationMismatchType: 'tag' | 'text'
69+
hydrationMismatchType: 'tag' | 'text' | 'text-in-tag'
7070
} & React.HTMLAttributes<HTMLPreElement>) {
7171
const isHtmlTagsWarning = hydrationMismatchType === 'tag'
7272
const isReactHydrationDiff = !!reactOutputComponentDiff

packages/next/src/client/components/react-dev-overlay/internal/helpers/hydration-error-info.ts

+50-9
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,62 @@ export const hydrationErrorState: HydrationErrorState = {}
1717

1818
// https://github.com/facebook/react/blob/main/packages/react-dom/src/__tests__/ReactDOMHydrationDiff-test.js used as a reference
1919
const htmlTagsWarnings = new Set([
20-
'In HTML, %s cannot be a child of <%s>.%s\nThis will cause a hydration error.%s',
21-
'In HTML, %s cannot be a descendant of <%s>.\nThis will cause a hydration error.%s',
22-
'In HTML, text nodes cannot be a child of <%s>.\nThis will cause a hydration error.',
23-
"In HTML, whitespace text nodes cannot be a child of <%s>. Make sure you don't have any extra whitespace between tags on each line of your source code.\nThis will cause a hydration error.",
20+
'Warning: In HTML, %s cannot be a child of <%s>.%s\nThis will cause a hydration error.%s',
21+
'Warning: In HTML, %s cannot be a descendant of <%s>.\nThis will cause a hydration error.%s',
22+
'Warning: In HTML, text nodes cannot be a child of <%s>.\nThis will cause a hydration error.',
23+
"Warning: In HTML, whitespace text nodes cannot be a child of <%s>. Make sure you don't have any extra whitespace between tags on each line of your source code.\nThis will cause a hydration error.",
24+
'Warning: Expected server HTML to contain a matching <%s> in <%s>.%s',
25+
'Warning: Did not expect server HTML to contain a <%s> in <%s>.%s',
2426
])
27+
const textAndTagsMismatchWarnings = new Set([
28+
'Warning: Expected server HTML to contain a matching text node for "%s" in <%s>.%s',
29+
'Warning: Did not expect server HTML to contain the text node "%s" in <%s>.%s',
30+
])
31+
const textMismatchWarning =
32+
'Warning: Text content did not match. Server: "%s" Client: "%s"%s'
33+
34+
export const getHydrationWarningType = (
35+
message: NullableText
36+
): 'tag' | 'text' | 'text-in-tag' => {
37+
if (typeof message !== 'string') {
38+
// TODO: Doesn't make sense to treat no message as a hydration error message.
39+
// We should bail out somewhere earlier.
40+
return 'text'
41+
}
42+
43+
const normalizedMessage = message.startsWith('Warning: ')
44+
? message
45+
: `Warning: ${message}`
46+
47+
if (isHtmlTagsWarning(normalizedMessage)) return 'tag'
48+
if (isTextInTagsMismatchWarning(normalizedMessage)) return 'text-in-tag'
2549

26-
export const getHydrationWarningType = (msg: NullableText): 'tag' | 'text' => {
27-
if (isHtmlTagsWarning(msg)) return 'tag'
2850
return 'text'
2951
}
3052

31-
const isHtmlTagsWarning = (msg: NullableText) =>
32-
Boolean(msg && htmlTagsWarnings.has(msg))
53+
const isHtmlTagsWarning = (message: string) => htmlTagsWarnings.has(message)
3354

34-
const isKnownHydrationWarning = (msg: NullableText) => isHtmlTagsWarning(msg)
55+
const isTextMismatchWarning = (message: string) =>
56+
textMismatchWarning === message
57+
const isTextInTagsMismatchWarning = (msg: string) =>
58+
textAndTagsMismatchWarnings.has(msg)
59+
60+
const isKnownHydrationWarning = (message: NullableText) => {
61+
if (typeof message !== 'string') {
62+
return false
63+
}
64+
// React 18 has the `Warning: ` prefix.
65+
// React 19 does not.
66+
const normalizedMessage = message.startsWith('Warning: ')
67+
? message
68+
: `Warning: ${message}`
69+
70+
return (
71+
isHtmlTagsWarning(normalizedMessage) ||
72+
isTextInTagsMismatchWarning(normalizedMessage) ||
73+
isTextMismatchWarning(normalizedMessage)
74+
)
75+
}
3576

3677
export const getReactHydrationDiffSegments = (msg: NullableText) => {
3778
if (msg) {

0 commit comments

Comments
 (0)