From 58b1fa5ed15edc7264785cd722282a011ea3042c Mon Sep 17 00:00:00 2001
From: ygj6 <7699524+ygj6@users.noreply.github.com>
Date: Wed, 22 Sep 2021 00:39:21 +0800
Subject: [PATCH] fix(hydration): ensure hydrated event listeners have bound
instance (#4529)
fix #4479
---
.../runtime-core/__tests__/hydration.spec.ts | 54 +++++++++++++++++++
packages/runtime-core/src/hydration.ts | 20 ++++++-
2 files changed, 72 insertions(+), 2 deletions(-)
diff --git a/packages/runtime-core/__tests__/hydration.spec.ts b/packages/runtime-core/__tests__/hydration.spec.ts
index 80258554b03..c5dbe539df9 100644
--- a/packages/runtime-core/__tests__/hydration.spec.ts
+++ b/packages/runtime-core/__tests__/hydration.spec.ts
@@ -461,6 +461,60 @@ describe('SSR hydration', () => {
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: `
+
+
+
`
+ }
+
+ 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: `
+
+
+
`
+ }
+
+ 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 () => {
const AsyncChild = {
async setup() {
diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts
index 939cf0ca1de..517b1495c11 100644
--- a/packages/runtime-core/src/hydration.ts
+++ b/packages/runtime-core/src/hydration.ts
@@ -287,13 +287,29 @@ export function createHydrationFunctions(
(forcePatchValue && key.endsWith('value')) ||
(isOn(key) && !isReservedProp(key))
) {
- patchProp(el, key, null, props[key])
+ patchProp(
+ el,
+ key,
+ null,
+ props[key],
+ false,
+ undefined,
+ parentComponent
+ )
}
}
} else if (props.onClick) {
// Fast path for click listeners (which is most often) to avoid
// iterating through props.
- patchProp(el, 'onClick', null, props.onClick)
+ patchProp(
+ el,
+ 'onClick',
+ null,
+ props.onClick,
+ false,
+ undefined,
+ parentComponent
+ )
}
}
// vnode / directive hooks