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