fix(ssr): avoid hydration mismatch warning for classes with different order

This commit is contained in:
Evan You 2023-12-20 10:48:01 +08:00
parent 048dffd7ee
commit e585b0db43
2 changed files with 29 additions and 3 deletions

View File

@ -1406,6 +1406,14 @@ describe('SSR hydration', () => {
mountWithHydration(`<div class="foo bar"></div>`, () => mountWithHydration(`<div class="foo bar"></div>`, () =>
h('div', { class: 'foo bar' }) h('div', { class: 'foo bar' })
) )
// SVG classes
mountWithHydration(`<svg class="foo bar"></svg>`, () =>
h('svg', { class: 'foo bar' })
)
// class with different order
mountWithHydration(`<div class="foo bar"></svg>`, () =>
h('div', { class: 'bar foo' })
)
expect(`Hydration class mismatch`).not.toHaveBeenWarned() expect(`Hydration class mismatch`).not.toHaveBeenWarned()
mountWithHydration(`<div class="foo bar"></div>`, () => mountWithHydration(`<div class="foo bar"></div>`, () =>
h('div', { class: 'foo' }) h('div', { class: 'foo' })

View File

@ -718,9 +718,11 @@ function propHasMismatch(el: Element, key: string, clientValue: any): boolean {
let actual: any let actual: any
let expected: any let expected: any
if (key === 'class') { if (key === 'class') {
actual = el.getAttribute('class') // classes might be in different order, but that doesn't affect cascade
expected = normalizeClass(clientValue) // so we just need to check if the class lists contain the same classes.
if (actual !== expected) { actual = toClassSet(el.getAttribute('class') || '')
expected = toClassSet(normalizeClass(clientValue))
if (!isSetEqual(actual, expected)) {
mismatchType = mismatchKey = `class` mismatchType = mismatchKey = `class`
} }
} else if (key === 'style') { } else if (key === 'style') {
@ -765,3 +767,19 @@ function propHasMismatch(el: Element, key: string, clientValue: any): boolean {
} }
return false return false
} }
function toClassSet(str: string): Set<string> {
return new Set(str.trim().split(/\s+/))
}
function isSetEqual(a: Set<string>, b: Set<string>): boolean {
if (a.size !== b.size) {
return false
}
for (const s of a) {
if (!b.has(s)) {
return false
}
}
return true
}