fix(hydration): ensure hydrated event listeners have bound instance (#4529)
fix #4479
This commit is contained in:
parent
d8a36d0198
commit
58b1fa5ed1
@ -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() {
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user