Переглянути джерело

fix(runtime-vapor): align interop unmount hook order with vdom

daiwei 3 тижнів тому
батько
коміт
13147d905d

+ 10 - 3
packages/runtime-core/src/renderer.ts

@@ -2424,10 +2424,17 @@ function baseCreateRenderer(
           invokeDirectiveHook(vnode, null, parentComponent, 'beforeUnmount')
         }
         getVaporInterface(parentComponent, vnode).unmount(vnode, doRemove)
-        if (dirs) {
+        if (
+          (shouldInvokeVnodeHook &&
+            (vnodeHook = props && props.onVnodeUnmounted)) ||
+          dirs
+        ) {
           queuePostRenderEffect(
-            () =>
-              invokeDirectiveHook(vnode, null, parentComponent, 'unmounted'),
+            () => {
+              dirs &&
+                invokeDirectiveHook(vnode, null, parentComponent, 'unmounted')
+              vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode)
+            },
             undefined,
             parentSuspense,
           )

+ 43 - 0
packages/runtime-vapor/__tests__/vdomInterop.spec.ts

@@ -362,6 +362,49 @@ describe('vdomInterop', () => {
       ])
     })
 
+    test('should invoke vnode and directive unmount hooks in VDOM order', async () => {
+      const calls: string[] = []
+      const vCustom = {
+        beforeUnmount: vi.fn(() => calls.push('directive beforeUnmount')),
+        unmounted: vi.fn(() => calls.push('directive unmounted')),
+      }
+
+      const VaporChild = defineVaporComponent({
+        setup() {
+          return template('<div>vapor</div>')()
+        },
+      })
+
+      const show = ref(true)
+      const { html } = define({
+        setup() {
+          return () =>
+            show.value
+              ? withDirectives(
+                  h(VaporChild as any, {
+                    onVnodeBeforeUnmount: () =>
+                      calls.push('vnode beforeUnmount'),
+                    onVnodeUnmounted: () => calls.push('vnode unmounted'),
+                  }),
+                  [[vCustom]],
+                )
+              : null
+        },
+      }).render()
+
+      expect(html()).toBe('<div>vapor</div>')
+
+      show.value = false
+      await nextTick()
+
+      expect(calls).toEqual([
+        'vnode beforeUnmount',
+        'directive beforeUnmount',
+        'directive unmounted',
+        'vnode unmounted',
+      ])
+    })
+
     test('should invoke update hooks in VDOM order on normal updates', async () => {
       const msg = ref('foo')
       const calls: string[] = []

+ 0 - 12
packages/runtime-vapor/src/vdomInterop.ts

@@ -267,18 +267,6 @@ const vaporInteropImpl: Omit<
       stopVaporSlotScope(vnode)
     }
     remove(vnode.anchor as Node, container)
-    // invoke onVnodeUnmounted hook
-    const vnodeHook = vnode.props && vnode.props.onVnodeUnmounted
-    if (vnodeHook) {
-      queuePostFlushCb(() => {
-        callWithAsyncErrorHandling(
-          vnodeHook,
-          instance && instance.parent,
-          ErrorCodes.VNODE_HOOK,
-          [vnode],
-        )
-      })
-    }
   },
 
   /**