]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(hydration): ensure hydrated event listeners have bound instance (#4529)
authorygj6 <7699524+ygj6@users.noreply.github.com>
Tue, 21 Sep 2021 16:39:21 +0000 (00:39 +0800)
committerGitHub <noreply@github.com>
Tue, 21 Sep 2021 16:39:21 +0000 (12:39 -0400)
fix #4479

packages/runtime-core/__tests__/hydration.spec.ts
packages/runtime-core/src/hydration.ts

index 80258554b03d56449de86be6ff07531777de682d..c5dbe539df933c0ad6f95d4178dde12de196f727 100644 (file)
@@ -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: `
+        <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 () => {
     const AsyncChild = {
       async setup() {
index 939cf0ca1de299aadad3648e949ee2d8296b95a8..517b1495c1111f0e387526c06ef0c4516ecbc370 100644 (file)
@@ -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