fix(hydration): ensure hydrated event listeners have bound instance (#4529)

fix #4479
This commit is contained in:
ygj6 2021-09-22 00:39:21 +08:00 committed by GitHub
parent d8a36d0198
commit 58b1fa5ed1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 72 additions and 2 deletions

View File

@ -461,6 +461,60 @@ describe('SSR hydration', () => {
expect(text.textContent).toBe('bye') expect(text.textContent).toBe('bye')
}) })
test('handle click error in ssr mode', async () => {
const App = {
setup() {
const throwError = () => {
throw new Error('Sentry Error')
}
return { throwError }
},
template: `
<div>
<button class="parent-click" @click="throwError">click me</button>
</div>`
}
const container = document.createElement('div')
// server render
container.innerHTML = await renderToString(h(App))
// hydrate
const app = createSSRApp(App)
const handler = (app.config.errorHandler = jest.fn())
app.mount(container)
// assert interactions
// parent button click
triggerEvent('click', container.querySelector('.parent-click')!)
expect(handler).toHaveBeenCalled()
})
test('handle blur error in ssr mode', async () => {
const App = {
setup() {
const throwError = () => {
throw new Error('Sentry Error')
}
return { throwError }
},
template: `
<div>
<input class="parent-click" @blur="throwError"/>
</div>`
}
const container = document.createElement('div')
// server render
container.innerHTML = await renderToString(h(App))
// hydrate
const app = createSSRApp(App)
const handler = (app.config.errorHandler = jest.fn())
app.mount(container)
// assert interactions
// parent blur event
triggerEvent('blur', container.querySelector('.parent-click')!)
expect(handler).toHaveBeenCalled()
})
test('Suspense', async () => { test('Suspense', async () => {
const AsyncChild = { const AsyncChild = {
async setup() { async setup() {

View File

@ -287,13 +287,29 @@ export function createHydrationFunctions(
(forcePatchValue && key.endsWith('value')) || (forcePatchValue && key.endsWith('value')) ||
(isOn(key) && !isReservedProp(key)) (isOn(key) && !isReservedProp(key))
) { ) {
patchProp(el, key, null, props[key]) patchProp(
el,
key,
null,
props[key],
false,
undefined,
parentComponent
)
} }
} }
} else if (props.onClick) { } else if (props.onClick) {
// Fast path for click listeners (which is most often) to avoid // Fast path for click listeners (which is most often) to avoid
// iterating through props. // iterating through props.
patchProp(el, 'onClick', null, props.onClick) patchProp(
el,
'onClick',
null,
props.onClick,
false,
undefined,
parentComponent
)
} }
} }
// vnode / directive hooks // vnode / directive hooks